ano*_*nol 6 c c99 undefined-behavior language-lawyer constant-expression
这是有效的C99代码吗?如果是这样,它是否定义了实现定义的行为?
int a;
unsigned long b[] = {(unsigned long)&a+1};
Run Code Online (Sandbox Code Playgroud)
根据我对C99标准的理解,从ISO C99标准中的§6.6,这可能是有效的:
整数常量表达式应具有整数类型,并且只能具有整数常量的操作数(...)整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof运算符的操作数的一部分.
初始化器中的常量表达式允许更大的纬度.这样的常量表达式应为或评估为以下之一:
- 算术常量表达式,
- (......)
- 对象类型的地址常量加上或减去整数常量表达式.
但是,由于存在添加溢出的可能性,因此可能不会将其视为常量表达式,因此无效C99代码.
有人可以确认我的推理是否正确吗?
请注意,即使使用,GCC和Clang也会在没有警告的情况下接受此代码-std=c99 -pedantic.但是,在转换时,unsigned int而不是unsigned long使用以下代码:
int a;
unsigned long b[] = {(unsigned int)&a+1};
Run Code Online (Sandbox Code Playgroud)
然后两个编译器都抱怨表达式不是编译时常量.
从这个 clang 开发人员线程中讨论了一个类似的问题:函数指针在转换为 long 但不是 int 时是编译时常量?理由是该标准不要求编译器支持这种情况(这种情况不包含在 中的任何项目符号中6.6p7),尽管允许支持这种情况,但支持截断的地址将是繁重的:
我假设你的 target 上的 sizeof(int) < sizeof(void(*)()) == sizeof(long)。问题是工具链几乎肯定无法将截断的地址表示为重定位。
C 仅要求实现支持初始值设定项值,这些值可以是 (1) 常量二进制数据,(2) 某个对象的地址,或者 (3) 或添加到某个对象地址的偏移量。我们被允许(但不是必需)支持更深奥的事情,例如减去两个地址或将地址乘以常数,或者如您的情况,截断地址的最高位。 这种计算需要从汇编器到加载器的整个工具链的支持,包括一路上的各种文件格式。这种支持通常不存在。
您将指针强制转换为整数类型的情况不适合6.6paragraph下的任何情况7:
初始值设定项中的常量表达式允许有更多的自由度。这样的常量表达式应为以下之一或计算结果为以下之一:
- 算术常量表达式,
- 空指针常量,
- 地址常量,或
- 对象类型的地址常量加上或减去整型常量表达式。
但正如后置编译器中提到的,允许支持其他形式的常量表达式:
实现可以接受其他形式的常量表达式。
但既不clang也不gcc接受这一点。
| 归档时间: |
|
| 查看次数: |
413 次 |
| 最近记录: |