1

u在 C++ 中,如果我从一个字符串中读取一个整数,那么我是否使用或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;
}

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

使用这些转换说明符进行解析(即传递给-type 函数的格式)之间u和使用时有什么区别吗?它是什么?dscanf

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

4

3 回答 3

9

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

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

于 2016-02-09T15:46:17.630 回答
1

从技术上讲,您在尝试使用格式说明符读取负数时调用了未定义的行为。您将指向有符号整数的指针视为指向无符号整数的指针,并且这些类型不兼容。它之所以有效,是因为无符号整数和有符号整数都具有相似的位表示,而有符号整数使用 2-补码表示。int%usscanf

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

于 2016-02-09T16:10:59.173 回答
1

每个转换说明符都有C 规范中定义的相应类型的结果参数。正如您所观察到的, %uand%d转换指令确实接受相同的输入,但对应的参数%u应该是 type unsigned int*,而不是int*。即您的示例应更正为:

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

如果您启用了警告,那么在编译原始示例时您会得到一个警告。理所当然地:

除非用 * 指示分配抑制,否则转换结果将放置在尚未收到转换结果的格式参数之后的第一个参数所指向的对象中。如果此对象没有适当的类型,或者转换的结果无法在对象中表示,则行为未定义。

强调我的。

因此,您正在调用未定义的行为(请参阅什么是未定义的行为部分)。一旦你调用了未定义的行为,你就会孤身一人,并且可能会发生令人讨厌的事情。


转换修饰符在C99(最新公开草案,N1256;官方 PDF)中定义。该定义与C11中的定义相同(最新公开草案,N1570;官方 PDF)。从C++ 标准文档列表中链接的最新 C++ 草案(截至 2015-02-10,N4567)在 Stack Overflow 上的另一个问题下采用了C99中标头的定义并且没有修改它(除了将函数放入命名空间和第 27.9.2 节中提到的微小修改)。cstdiostd

于 2016-02-10T17:28:54.667 回答