c - 作为具有静态持续时间的对象的初始值设定项的指针

c - pointer as an initializer for an object with static duration

我。问题的背景。

关于标准的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.

至于6.2.4。 3) 标准:

An object whose identifier is declared with external or internal linkage, or with the storage-class specifier static has static storage duration.

至于6.6。 7) 标准:

More latitude is permitted for constant expressions in initializers.

和 6.6。 9):

An address constant is a null pointer,a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; ...

终于在6.3.2.1。 1) 我们阅读:

An lvalue is an expression with an object type or an incomplete type other than void;

二.问题.

我在 object.h 中有以下声明:

 struct class_check_s {
     char blank;
 };
 struct class_check_s class_check = { 0 };
 struct class_check_s *passed = &class_check;

struct object_vt_s {
    /* ... */
    struct class_check_s *safecheck;
    /* ... */
};

object.hinclud 编辑成 object.c ,其中我有以下代码:

struct object_vt_s object_vt = {
    /* ... */
    .safecheck= passed,
    /* ... */
};

gcc.safecheck= passed 部分大喊:

error: initializer element is not constant

clang 类似:

error: initializer element is not a compile-time constant

但我认为我的情况低于 6.6。 9).我猜不会?我找不到确切原因的答案。


我正在做的是一个主要用于学习目的的小 oop 模块。我正在尝试在对象的“方法”内部实现某种动态类型检查。

6.6 9 中“指向左值的指针……”的意思是 pointer-value 左值,即左值的地址。虽然您的 struct class_check_s *passed 被称为“指针”,但更具体地说,它是一个值为指针的对象。当你写 .safecheck = passed 时,你并没有给编译器它想要的初始化值;你告诉它从 passed.

中获取值

你可以写 .safecheck = &class_check。这会将 safecheck 初始化为 class_check 的地址,并且编译器能够向链接器描述该地址,以便程序加载器可以在程序启动时正确调整其值。

但是,对于 .safecheck = passed,编译器名义上必须从存储中读取 passed 的值。理论上,一个好的编译器可以查看 passed 的初始化,看到它被初始化为 &class_check,并使用该值进行初始化。 C 标准并没有正式禁止这样做,但它并不要求这样做,而且这是不寻常的。此外,请注意这里的语义有点不稳定:passed 未声明 [​​=21=],因此它的值可能会更改,那么为什么在编译 .safecheck = passed 时要使用它的任何特定值?当然,这都是“compile-time”的东西,但那是在 C 语言中添加 C 标准未指定的语义。就 C 的语义而言,passed 在程序开始执行之前不存在(没有为其保留存储空间)。