我遇到了一些代码,并想知道它是不是只是一个侥幸它按预期工作或只是不好的做法。考虑以下MCVE(ideone):
#include <cstdio>
struct dummyStruct
{
unsigned short min[4];
unsigned short max[4];
int dummyBuffer; // This just happens to be here as a real variable in the original code, not just as a buffer.
};
int main()
{
dummyStruct db;
// Note that the size of the short is assumed to be half of that of the %d specifier
sscanf(" 123, 456, 789, 112", "%d, %d, %d, %d", db.min+0, db.min+1, db.min+2, db.min+3);
sscanf("29491, 29491, 29491, 29491", "%d, %d, %d, %d", db.max+0, db.max+1, db.max+2, db.max+3);
db.dummyBuffer = 1234;
printf("%hd, %hd, %hd, %hd\n", db.min[0], db.min[1], db.min[2], db.min[3]);
printf("%hd, %hd, %hd, %hd\n", db.max[0], db.max[1], db.max[2], db.max[3]);
printf("%d\n", db.dummyBuffer);
return 0;
}
结构的内容是由标准保证的,还是这种未定义的行为?我在N4810没有提到这一点。或者,如果我们颠倒变量的顺序,例如
printf("%hd, %hd, %hd, %hd\n", db.min[0], db.min[2], db.min[1], db.min[3]);
db.min
的内容有保证吗?参数的顺序(从左到右)是赋值的顺序吗?另请注意,即使已定义,我也不会问为什么这是不好的做法。我也不需要评论告诉我不要使用scanf
。我不是。
你在N4810中没有提到,因为当谈到C标准库时,规范主要推迟到“ISO / IEC 9899:2011,编程语言 - C”。如果我们看一下N1570(C11草案),就会说scanf
系列功能:
7.21.6.2 fscanf函数(强调我的)
10除了%说明符之外,输入项(或者,在%n指令的情况下,输入字符的数量)将转换为适合转换说明符的类型。如果输入项不是匹配序列,则指令的执行失败:此条件是匹配失败。除非通过*指示赋值抑制,否则转换的结果将放在由尚未收到转换结果的format参数后面的第一个参数指向的对象中。如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义。
因此,您的样本工作确实是由于未定义的行为而产生的侥幸。