可以将int的地址传递给scanf(“%x”,...)吗?

时间:2018-09-20 08:52:50

标签: c scanf language-lawyer undefined-behavior

以下代码是否已定义beavior:

#include <stdio.h>

int main() {
    int x;
    if (scanf("%x", &x) == 1) {
        printf("decimal: %d\n", x);
    }
    return 0;
}

clang即使启用了所有警告(包括-pedantic),也不会产生任何警告地对其进行编译。 C标准对此毫不含糊:

  

C17 7.21.6.2 fscanf功能

     

...

     

...转换结果放置在尚未接收转换结果的format参数后面的第一个参数指向的对象中。如果此对象的类型不合适,或者无法在对象中表示转换结果,则该行为是不确定的。

     

...

     

转换说明符及其含义为:

     

...

     

x匹配一个可选的带符号的十六进制整数,其格式与strtoul函数的主题序列所期望的格式相同,且16参数的值为base 。相应的参数应为指向无符号整数的指针。

在二进制补码体系结构中,将-1转换为%x似乎是可行的,但是在古代的符号/幅值或一个补码系统上则无效。

是否有任何规定可以定义此行为或至少定义实现?

1 个答案:

答案 0 :(得分:1)

这属于质量实现应支持的行为类别,除非它们记录了这样做的充分理由,但本标准未强制要求这样做。该标准的作者似乎没有尝试列出所有此类行为,并且至少有三个充分的理由:

  1. 这样做会延长标准的时间,而花墨水描述读者无论如何都会期望的明显行为,将分散注意力,使标准无法吸引人们注意本来不会期望的事情。< / p>

  2. 该标准的作者可能并不想排除某个实现可能有充分理由做一些不寻常的事情的可能性。我不知道在您的特定情况下这是否是一个考虑因素,但是本来可以考虑的。

    例如,考虑一个(可能是理论上的)环境,该环境的调用约定要求传递有关传递给可变参数函数的参数类型的信息,并且提供一个scanf函数来验证那些参数类型并在传递int*的情况下发出叫声%X参数。该标准的作者几乎肯定不了解任何这样的环境(我怀疑是否存在过这种环境),因此无法权衡使用环境的scanf例程的好处与支持常见行为的好处。因此,将这样的判断留给那些能够更好地评估每种方法的成本和收益的人是有意义的。

  3. 对于本标准的作者来说,要确保他们详尽地列举所有此类案例而不遗漏任何案例都是极其困难的,并且他们尝试列举此类案例的方式越详尽,则越有可能意外遗漏会被误认为是故意的。

在实践中,一些编译器作者似乎将标准未能授权某种行为的大多数情况视为邀请代码假设它永远不会尝试的行为,即使该标准之前的所有实现都表现一致,并且不太可能否则将有充分的理由要执行此操作。因此,使用%X来读取int属于行为的类别,这种行为对于那些努力与常见习语兼容的实现是可靠的,但在设计者赋予更高价值的实现中可能会失败能够更有效地处理无用的程序,或者旨在防止某些给定程序破坏的实现。

相关问题