sscanf(s, "%u", &v) 匹配有符号整数

sscanf(s, "%u", &v) matching signed integers

在 Cppcheck 抱怨 "%u" 作为扫描到 int 变量的错误格式说明符之后,我将格式更改为 "%d",但是当再次查看它时在进行更改之前,我认为其目的可能是为了防止负输入。我写了两个小程序来看看区别:

说明符 %d

#include <iostream>
#include <stdlib.h>
using namespace std;

int main() {
    const char* s = "-4";
    int value = -1;
    int res = sscanf(s, "%d", &value);
    cout << "value:" << value << endl;
    cout << "res:" << res << endl;
    return 0;
}

另见 https://ideone.com/OR3IKN

说明符 %u

#include <iostream>
#include <stdlib.h>
using namespace std;

int main() {
    const char* s = "-4";
    int value = -1;
    int res = sscanf(s, "%u", &value);
    cout << "value:" << value << endl;
    cout << "res:" << res << endl;
    return 0;
}

另见 https://ideone.com/WPWdqi

结果

令人惊讶的是,两个转换说明符都接受符号:

value:-4
res:1

我查看了 cppreference.com 上的文档。对于 C (scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s - cppreference.com) as well as C++ (std::scanf, std::fscanf, std::sscanf - cppreference.com),"%u" 转换说明符的描述是相同的(强调我的):

matches an unsigned decimal integer.
The format of the number is the same as expected by strtoul() with the value 10 for the base argument.

观察到的行为是否符合标准?我在哪里可以找到这个文档?

[更新] 未定义的行为,真的,为什么?

我读到它是 , well, to add to the confusion, here is the version declaring value as unsigned https://ideone.com/nNBkqN - 我认为 -1 的分配仍然符合预期,但“%u”显然仍然匹配符号:

#include <iostream>
#include <stdlib.h>

using namespace std;

int main() {
    const char* s = "-4";
    unsigned value = -1;
    cout << "value before:" << value << endl;
    int res = sscanf(s, "%u", &value);
    cout << "value after:" << value << endl;
    cout << "res:" << res << endl;
    return 0;
}

结果:

value before:4294967295
value after:4294967292
res:1

不,它不符合标准。事实上,您的程序的行为是 undefinedsscanf 的格式说明符必须匹配参数的类型。

有两个不同的问题。

  1. %u 需要一个 unsigned int* 参数;传递一个 int* 是 UB.
  2. %u 匹配 -4 吗?是的。预期格式是以 10 为底的 strtoul,如果您阅读 the documentation,则很明显允许使用前导减号。