在 C 中使用整数转换的全局变量指针初始化全局变量

Initializing a global variable with integer-casted global variable pointer in C

我发现了一个意外的 'invalid' C 代码片段,我认为这是一个有效的代码片段:

char str[] = "test string";
int pstr2 = (int)str;

第二行引发以下编译错误:

main.c:2:12: error: initializer element is not a compile-time constant
int pstr = (int)str;
           ^~~~~~~~
1 error generated.

似乎强制转换的全局变量不是编译时常量,尽管正常的是。 C规范的哪一部分使第二行错误?

P.S. 我刚刚编写代码来重现我遇到的 LLVM 后端错误。无论如何感谢您的提示:)

我相信,你在做

int pstr = (int)str;

全局 space 中。 语句 不允许存在于全局范围内。它需要在功能范围内。

一种特殊情况,定义时初始化是允许的,但条件是初始化器必须是编译时常量。

这里,str不是编译时常量值。因此错误。

FWIW,"test string" 是一个未命名的 字符串文字 ,允许用作初始值设定项。所以,第一个语句是允许的。

此外,使用 int pstr2 = (int)str; 是危险的,因为无法保证指针是否适合 int

如果这段代码是全局级别的,即在函数之外,则第二行确实无效。全局变量只能用常量表达式初始化。

任何其他内容都是语句,必须驻留在函数中。

Which part of C specification makes this erroneous?

由于pstr是全局的,所以它有静态存储期限。因此,C99标准的第6.7.8.4节适用:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

"test string" 的地址要到link 时才能解析,而将地址转换为int 需要对link 时的值进行计算。这使得 (int)str 在此上下文中无效。

注意link-时间常数无需计算是允许的,例如

char *pstr = str;

完全有效,因为没有转换。

注意: 由于 int 不能保证完整保存指针,请考虑使用 intptr_tuintptr_t 类型。

这不是常量,因为转换为 int 可能需要转换,例如在 Linux x86_64 系统上,其中 sizeof(int) 是 4 而 sizeof(void *) 是 8。通常,将指针转换为整数类型总是需要转换,即使您使用 intptr_t(你应该...),因为这实际上可能比你的指针大。

相比之下,以下代码可以工作:

typedef struct { char foo[1]; } test_t;
char str[] = "test string";
test_t *pstr2 = (test_t *)str;

所以问题不在于演员表本身。