scanf(“%d%d”,&x,&x)是否定义良好?

以下代码是否定义良好?

#include  int ScanFirstOrSecond(const char *s, int *dest) { return sscanf(s, "%d%d", dest, dest); } int main(void) { int x = 4; ScanFirstOrSecond("5", &x); printf("%d\n", x); // prints 5 // Here is the tricky bit ScanFirstOrSecond("6 7", &x); printf("%d\n", x); // prints 7 return 0; } 

换句话说, ...参数是否有隐含的restrict

我发现最适用的C规范是

fscanf函数依次执行格式的每个指令。 ……C11dr§7.21.6.24

简短的回答是: 是的,定义如下:

scanf将尝试将stdin的字节序列转换为基数为10的整数,并带有可选的初始空格和可选符号。 如果成功,该号码将存储到x 。 然后scanf将再次执行这些步骤。 返回值可以是EOF02 ,对于后者2,最后转换的数字将存储到x

冗长的答案有点夸张:

似乎C标准确实指定值以格式字符串的顺序存储。 引用C11标准:

7.21.6.2 fscanf函数

4 fscanf函数依次执行格式的每个指令。 当所有指令都已执行,或者指令失败时(如下所述),函数返回。

7作为转换规范的指令定义了一组匹配的输入序列,如下面针对每个说明符所述。 转换规范按以下步骤执行:

10除了%说明符之外,输入项(或者,在%n指令的情况下,输入字符的数量)将转换为适合转换说明符的类型。 如果输入项不是匹配序列,则指令的执行失败:此条件是匹配失败。 除非用*指示赋值抑制,否则转换的结果将放在由尚未收到转换结果的format参数后面的第一个参数指向的对象中。

16如果在第一次转换(如果有)完成之前发生输入故障, fscanf函数将返回宏EOF的值。 否则,该函数返回分配的输入项的数量,如果早期匹配失败,则可以少于提供的数量,甚至为零。

本规范中的任何其他地方都没有对提到的输出对象的任何访问。

然而,标准的措辞似乎表明,如果2个指针指向同一个对象,则行为可能是意外的: 转换的结果放在第一个参数指向的对象之后,该参数是在尚未收到的格式参数之后转换结果。 这句话有些含糊不清: 尚未收到转换结果的是什么? 对象或论点? 对象接收转换结果,而不是指针参数。 在您的扭曲示例中,对象x已经收到转换结果,因此它不应该接收另一个…但正如supercat所指出的,这种解释具有明显的限制性,因为它意味着所有转换后的值都存储在第一个目标中宾语。

因此它看起来完全明确并且定义明确,但是可以完善规范的措辞以消除潜在的模糊性。

scanf()系列函数严格依次执行格式字符串中保留的指示。 因此,第一个值将被读入,然后第二个值将覆盖第一个值。 没有UB在这里。

是的,定义明确。 这意味着“将第一个令牌读入* dest,然后再将第二个令牌读入* dest”。 这很奇怪但合法。 是的,因为sscanf()按严格的顺序执行格式字符串中的指令。