c - 具有常量表达式的初始化程序在 C99 中可能溢出

标签 c language-lawyer c99 undefined-behavior constant-expression

这是有效的 C99 代码吗?如果是,它是否定义了实现定义的行为?

int a;
unsigned long b[] = {(unsigned long)&a+1};

根据我对 C99 标准的理解,从 ISO C99 标准的 §6.6 开始,这可能是有效的:

  1. An integer constant expression shall have integer type and shall only have operands that are integer constants (...) Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.

  2. More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:

    • an arithmetic constant expression,
    • (...)
    • an address constant for an object type plus or minus an integer constant expression.

但是,由于存在加法溢出的可能性,这可能不被视为常量表达式,因此不是有效的 C99 代码。

有人可以确认我的推理是否正确吗?

请注意,即使在使用 -std=c99 -pedantic 时,GCC 和 Clang 都会在没有警告的情况下接受此代码。但是,当转换为 unsigned int 而不是 unsigned long 时,即使用以下代码:

int a;
unsigned long b[] = {(unsigned int)&a+1};

然后两个编译器都提示该表达式不是编译时常量。

最佳答案

来自此 clang 开发人员线程中的类似问题:Function pointer is compile-time constant when cast to long but not int?理由是该标准不要求编译器支持此功能(此场景未包含在 6.6p7 的任何项目符号中),尽管它被允许支持此功能支持截断地址会很麻烦:

I assume that sizeof(int) < sizeof(void(*)()) == sizeof(long) on your target. The problem is that the tool chain almost certainly can't express a truncated address as a relocation.

C only requires the implementation to support initializer values that are either (1) constant binary data, (2) the address of some object, or (3) or an offset added to the address of some object. We're allowed, but not required, to support more esoteric things like subtracting two addresses or multiplying an address by a constant or, as in your case, truncating the top bits of an address away. That kind of calculation would require support from the entire tool chain from assembler to loader, including various file formats along the way. That support generally doesn't exist.

您的情况是将指针转换为整数类型,不适合 6.6 段落 7 下的任何情况:

More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:

  • an arithmetic constant expression,
  • anull pointer constant,
  • an address constant, or
  • an address constant for an object type plus or minus an integer constant expression.

但如post编译器中所述允许支持其他形式的常量表达式:

An implementation may accept other forms of constant expressions.

但是 clanggcc 都不接受这个。

关于c - 具有常量表达式的初始化程序在 C99 中可能溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29652323/

相关文章:

c++ - 是否有默认设置为 -1>>1 != -1 的 C99 编译器?

c - 从 Ruby 访问 C 项目上的 dll 函数

c - 构建项目存在哪些替代环境?

c++ - 条件运算符的值类别

c - 返回包含数组的结构

C99 可变长度数组维基百科示例

c - VS2013对C99支持的官方状态是什么?

ios - 如何访问 C 函数中的对象

c - 从世界位置获取屏幕位置

c++ - 当 A 和 B 为 "the same"时断言(sizeof(A) == sizeof(B)) 是否安全?