gha*_*.st 10 c gcc clang language-lawyer c11
C11标准ISO/IEC 9899:2011(E)规定了§6.5.16.1/ 1中简单指配的以下约束:
以下其中一项应持有:
- 左操作数具有原子,限定或非限定算术类型,右边有算术类型;
- 左操作数具有与右侧类型兼容的结构或联合类型的原子,限定或非限定版本;
- 左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有全部右边指出的那种限定词;
- 左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的指针void,左边指向的类型具有右边指向的所有类型的限定符;
- 左操作数是一个原子,限定或非限定指针,右边是一个空指针常量; 要么
- 左操作数的类型为atomic,qualified或nonqualified
_Bool,右边是指针.
我感兴趣的是双方都指向不兼容的不同类型的情况void.如果我理解正确,这应该至少调用UB,因为它违反了这个约束.不兼容类型的一个例子应该是(根据§6.2.7和§6.7.2)int和double.
因此,以下程序应违反:
int main(void) {
int a = 17;
double* p;
p = &a;
(void)p;
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang都警告"-Wincompatible-pointer-types",但不要中止编译(编译-std=c11 -Wall -Wextra -pedantic).
同样,以下程序只会导致"-Wint-conversion"警告,同时编译就好了.
int main(void) {
int a;
double* p;
p = a;
(void)p;
}
Run Code Online (Sandbox Code Playgroud)
来自C++,我预计这些测试用例中的任何一个都需要使用强制转换来编译.是否有任何理由为什么这两个计划都是标准合法的?或者,是否至少有重要的历史原因支持这种代码风格,即使通过明确使用-std=c11而不是禁用有趣的GNU C扩展-std=gnu11?
有什么理由说明这两个程序都符合标准吗?
这些程序不是“标准合法的”。它们包含违反约束,并且您已经引用了标准中的正确文本。
编译器通过生成违反约束的诊断来符合标准。该标准不要求在违反约束或其他错误程序的情况下中止编译。
它没有用太多的话来说明,但唯一合理的结论是,由于包含违反约束的程序而生成的任何可执行文件都具有完全未定义的行为。(不过,我已经看到人们试图以其他方式争论)。
推测如下:C(和 C++)有多种用途;有时人们希望他们的机器有“高级汇编程序”,而不关心便携性或标准。据推测,编译器供应商将默认值设置为他们认为目标受众更喜欢的。
请求检查严格标准一致性并拒绝编译不合格代码的编译器标志(gcc 和 clang)是-pedantic-errors:
$ gcc -std=c11 -pedantic-errors x.c\nx.c: In function \xe2\x80\x98main\xe2\x80\x99:\nx.c:3:15: error: initialization from incompatible pointer type [-Wincompatible-pointer-types]\n double* p = &a;\n ^\nRun Code Online (Sandbox Code Playgroud)\n\n铛:
\n\n$ clang -std=c11 -pedantic-errors x.c\nx.c:3:11: error: incompatible pointer types initializing 'double *' with an\n expression of type 'int *' [-Werror,-Wincompatible-pointer-types]\n double* p = &a;\n ^ ~~\n1 error generated.\nRun Code Online (Sandbox Code Playgroud)\n\n很大一部分(至少可以说)典型的 C 代码在野外是不合格的,因此-pedantic-errors会导致大多数 C 程序和库无法编译。
| 归档时间: |
|
| 查看次数: |
348 次 |
| 最近记录: |