在C ++中,如果我从字符串中读取一个整数,那么我使用u
或d
作为转换说明符似乎并不重要,因为它们都接受负整数。
#include <cstdio>
using namespace std;
int main() {
int u, d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);
puts(u == d ? "u == d" : "u != d");
printf("u: %u %d\n", u, u);
printf("d: %u %d\n", d, d);
return 0;
}
我挖得更深,发现是否有任何区别。我找到了
int u, d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);
相当于
int u, d;
u = strtoul("-2", NULL, 10);
d = strtol("-2", NULL, 10);
使用这些转换说明符进行解析时,u
和d
之间是否存在任何差异,即传递给scanf
类型函数的格式?它是什么?
C和C ++的答案是一样的,对吧?如果没有,我对两者都感兴趣。
答案 0 :(得分:9)
%d
:将整数扫描为小数signed int
。 类似的转换说明符%i
在前面加0x
时将数字解释为十六进制,并在前面加0
时将其解释为八进制。否则,它是相同的。
%u
:将整数扫描为小数unsigned int
。
答案 1 :(得分:1)
从技术上讲,当您尝试使用int
格式说明符将负数读入%u
时,您正在调用未定义的行为。您使sscanf
将指向有符号整数的指针视为指向无符号整数的指针,并且这些类型不兼容。它只能起作用,因为无符号和有符号整数都具有类似的位表示,有符号整数使用2补码表示。
TL / DR:您不能保证从sscanf("-2", "%u", &u);
答案 2 :(得分:0)
每个conversion specifier都有一个相应的类型的结果参数在C规范中定义。正如您所观察到的, %u
和%d
转换指令确实接受相同的输入,但与%u
对应的参数应为类型unsigned int*
,而不是int*
。即您的示例应更正为:
unsigned int u;
int d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);
如果您启用了警告,则在编译原始示例时会得到警告。 rightfully so:
除非用*指示赋值抑制,否则转换的结果将放在由尚未收到转换结果的format参数后面的第一个参数指向的对象中。 如果此对象没有合适的类型,或者无法在对象中表示转换结果,则行为未定义。
强调我的。
所以,你正在调用undefined behavior(参见什么是未定义的行为部分)。一旦你调用了未定义的行为,你就会孤身一人,并且可能会发生令人讨厌的事情。
转换修饰符在C99中定义(最新公开草案,N1256; official PDF)。定义与C11中的定义相同(最新公开草案,N1570; official PDF)。关于Stack Overflow上另一个问题下most recent C++ draft链接的list of C++ standard documents(截至2015-02-10,N4567)采用cstdio
标题from C99和{{3的定义(除了does not modify it和placing the functions into the std
namespace中提到的次要修改)。