scanf()中%u和%d之间的差异

时间:2016-02-09 15:43:04

标签: c++ scanf cstdio

在C ++中,如果我从字符串中读取一个整数,那么我使用ud作为转换说明符似乎并不重要,因为它们都接受负整数。

#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;
}

Ideone.com

我挖得更深,发现是否有任何区别。我找到了

int u, d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);

相当于

int u, d;
u = strtoul("-2", NULL, 10);
d = strtol("-2", NULL, 10);

根据cppreference.com

使用这些转换说明符进行解析时,ud之间是否存在任何差异,即传递给scanf类型函数的格式?它是什么?

C和C ++的答案是一样的,对吧?如果没有,我对两者都感兴趣。

3 个答案:

答案 0 :(得分:9)

%d:将整数扫描为小数signed int类似的转换说明符%i在前面加0x时将数字解释为十六进制,并在前面加0时将其解释为八进制。否则,它是相同的。

%u:将整数扫描为小数unsigned int

答案 1 :(得分:1)

从技术上讲,当您尝试使用int格式说明符将负数读入%u时,您正在调用未定义的行为。您使sscanf将指向有符号整数的指针视为指向无符号整数的指针,并且这些类型不兼容。它只能起作用,因为无符号和有符号整数都具有类似的位表示,有符号整数使用2补码表示。

TL / DR:您不能保证从sscanf("-2", "%u", &u);

获得-2

答案 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 itplacing the functions into the std namespace中提到的次要修改)。