【发布时间】:2016-08-18 03:29:52
【问题描述】:
C11 标准 ISO/IEC 9899:2011 (E) 在 §6.5.16.1/1 中规定了以下简单分配的约束:
应满足以下条件之一:
- 左侧操作数具有原子、合格或不合格算术类型,右侧具有 算术类型;
- 左操作数具有结构或联合的原子、合格或不合格版本 类型与权利的类型兼容;
- 左操作数具有原子、限定或非限定指针类型,并且(考虑到 左操作数在左值转换后的类型)两个操作数都是 指向兼容类型的合格或非合格版本的指针,以及指向的类型 to by left 具有所有由 right 指向的类型的限定符;
- 左操作数具有原子、限定或非限定指针类型,并且(考虑到 左操作数在左值转换后的类型)一个操作数是一个指针 指向一个对象类型,另一个是指向一个合格或不合格版本的指针 void,并且左边指向的类型具有指向的类型的所有限定符 靠右;
- 左边的操作数是一个原子的、合格的或不合格的指针,右边是一个空指针 指针常量;或
- 左侧操作数的类型为 atomic、合格或不合格
_Bool,右侧是指针。
我对双方都是指向不同于void 的不兼容 类型的指针的情况感兴趣。如果我理解正确,这至少应该调用 UB,因为它违反了这个约束。不兼容类型的一个示例应该是(根据 §6.2.7 和 §6.7.2)int 和 double。
因此下面的程序应该是违规的:
int main(void) {
int a = 17;
double* p;
p = &a;
(void)p;
}
gcc 和 clang 都对“-Wincompatible-pointer-types”发出警告,但不要中止编译(使用 -std=c11 -Wall -Wextra -pedantic 编译)。
同样,以下程序只会导致“-Wint-conversion”警告,而编译正常。
int main(void) {
int a;
double* p;
p = a;
(void)p;
}
来自 C++,我预计这些测试用例中的任何一个都需要强制转换才能编译。有什么理由可以说明这两个程序都符合标准吗?或者,即使通过显式使用 -std=c11 而不是 -std=gnu11 来禁用有趣的 GNU C 扩展,是否至少有重要的历史原因支持这种代码风格?
【问题讨论】:
标签: c gcc clang language-lawyer c11