uint8_t,uint16_t等的格式说明符是什么?

61

如果我有一个整数变量,我可以使用以下所示的格式说明符%d来使用sscanf

sscanf (line, "Value of integer: %d\n", &my_integer);

我在哪里可以找到uint8_tuint16_tuint32_tuint64_t的格式说明符?

uint64_t 可能有 %lu。


%lu 不是用于 unsigned long 吗?通常是 32 位。 - MSalters
5
如果您使用适应于类型的iostreams,也没有问题。 - Sebastian Mach
1
@MSalters:请注意,对于64位目标,Windows 64位的“unsigned long”是32位,而所有UNIX和Linux 64位的“unsigned long”都是64位。 - Didier Trosset
3
unsigned long 在所有的 64 位 UNIX 变种系统上并不是 64 位。在使用 GCC 的 64 位 Solaris 上它是32位的。我曾经有一次非常痛苦的经历,因为我学到它在 Linux 上是64位的。 - camelccc
根据这里所解释的内容:http://www.unix.org/version2/whatsnew/lp64_wp.html,64位的Solaris应该是UNIX中LP64的一个例外。 - Didier Trosset
7个回答

97

它们在<inttypes.h>中声明为宏:SCNd8、SCNd16、SCNd32和SCNd64。 例如(针对int32_t):

sscanf (line, "Value of integer: %" SCNd32 "\n", &my_integer);

他们的格式是PRI(用于printf)/SCN(用于scan),然后是相应指示符的o、u、x、Xd、i,然后是无大小、LEAST、FAST、MAX的选项,然后是大小(显然对于MAX没有大小)。其他一些例子:PRIo8、PRIuMAX、SCNoFAST16。
编辑:顺便说一下,related question问为什么使用这种方法。您可能会发现答案很有趣。

5
uint32_t 应使用 SCNu32,而 int32_t 应使用 SCNi32 - Sander De Dycker
1
-1:除非作为非标准扩展,否则它们不会在那里声明。 - Sebastian Mach
1
@phresnel,一个关于int8_t的问题显然假设使用的要么是C++0X,要么是在标准之前导入了这些来自C99的扩展。在第一种情况下,<inttypes.h> 存在,在第二种情况下,假设我知道的实现同时导入了<inttypes.h><stdint.h>,这是一个相当安全的打赌。 - AProgrammer
由于这是一个流行的问答,建议就一个相关问题发表评论:scanf() 格式中的结尾 '\n' 会带来一些问题。 - chux - Reinstate Monica

7

如其他人所说,需要包含定义格式宏的<stdint.h>头文件。但在C ++中,在包含它之前请先定义__STDC_FORMAT_MACROS。从stdint.h:

/* The ISO C99 standard specifies that these macros must only be
   defined if explicitly requested.  */
#if !defined __cplusplus || defined __STDC_FORMAT_MACROS

4
根据C++0X规范:“<cinttypes>定义的宏是无条件提供的。特别地,C标准文档182脚注中提到的__STDC_FORMAT_MACROS符号在C++中没有任何作用。” 但定义__STDC_FORMAT_MACROS可能有助于使用未更新以遵循C++0X的扩展。 - AProgrammer

2
根据《ISO/IEC 9899:TC2》中的“7.19.6格式化输入/输出函数”,没有这样的格式说明符(因此我怀疑C++2003是否有)。即使在C99的中有一些#define宏可用,但和不是当前标准的一部分。当然,固定大小的整数类型也是非标准的。
无论如何,我强烈建议使用流代替。
<any_type> x;
f >> x;

并完成。例如:

std::stringstream ss;
uint32_t u;
std::cin >> u;

这样做的好处在于,将来更改变量类型时不会导致一系列微妙的错误和未定义的行为。

在VC++ 2010上,使用“>>”比fscanf慢得多,大约2-3倍。 - sergtk
1
@sergtk:这是一个特性。默认情况下,iostreams 与 C 函数同步。您可以禁用此功能,结果将是 iostreams 至少与其同步速度一样快。 - Sebastian Mach
我想你是指std::ifstream.sync_with_stdio(false)。这并不能显著提高速度。此外,如果使用<<运算符读取字符串,然后使用sscanf解析,则速度几乎与fscanf相同。这意味着使用iostream解析值比较慢,而这与sync无关。 - sergtk
@sergtk:嗯,我的基准测试结果并不是这样的:https://dev59.com/d2kw5IYBdhLWcg3woMJD#9747716 和 https://dev59.com/DnI-5IYBdhLWcg3wF0Uc#9212163。而且我不确定为什么你想使用`<<,然后用sscanf作为fscanf`的替代方案。 - Sebastian Mach
第一个链接包含测试字符读取时,这不涉及类型转换。第二个链接更有趣,因为它已经包含了int-s。但我们使用了不同的编译器。我主要使用int-s和float-s进行测试。更有趣的是,事实上,在我的测试中所有文件读取仍然使用std::ifstream。但最初它是用来使用“<<”读取任何类型的。但优化版本使用getline(ifstream&,string&)读取字符串,然后使用sscanf解析字符串。性能的提高只是因为使用了其他类型的转换,而不是通过优化读取数据。 - sergtk

0

读取 uint64_t(typedef unsigned long long int)的正确格式是使用 scanf 而不是 sscanf,格式为 "%" SCNu64,打印同样也是使用 SCNu64。 例如,在您的代码中,您读取了变量 my_integer,然后执行以下操作: scanf ("Value of integer:%" SCNu64, & my_integer);,如果要使用 printf 输出相同的内容,则可以这样写。


0
在C语言中,头文件是<inttypes.h>,格式如SCNX8、SCNd16。
同样的头文件可能也适用于C++。

2
在C++标准中,<inttypes.h><stdint.h>(声明了int8_t等typedef)同时被引入,正式地出现在C++0X中,但在实践中作为扩展在与C99实现有强关联的实现中可用。 - AProgrammer

0

你可以在C++中的<cstdint>或者C中的<types.h>中检查类型。然后你可以指定当前编译在你的机器上的格式。 如果变量是unsigned,那么你需要使用%u,如果变量是signed,那么使用%d。对于小于32字节的变量大小,你不需要指定长前缀。

在我的配置中,我有一个64位程序,所以我的uint64_t被编译为unsigned long long int,所以意味着要使用%llu。如果你的程序将在32位编译,你可以使用%lu,因为uint64_t将被编译为unsigned long int

但是还有谁在使用x86呢?:)

uint8_t, uint16_t, uint32_t - %u
uint64_t - %llu
int8_t, int16_t, int32_t - %d
int64_t -%lld

1
请在您的回答中添加一些解释,以便其他人可以从中学习。 - Nico Haase

-2

请参考 this 了解 sscanf 的用法。

这些数据类型在 stdint.h 中定义。请参考此处查看 stdint.h

Shash


引用并不等同于回答。它主要告诉你自己不知道。 - Sebastian Mach
我不相信如果可以在网络上找到的话就复制粘贴!这就像连接点一样,sscanf和stdint,你觉得呢? - Shash316
2
但是stackoverflow的答案本身应该保持有效。至少告诉在http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/上如何格式化int64等。 - Sebastian Mach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接