【问题标题】:does nested struct initialization depend on scope?嵌套结构初始化是否取决于范围?
【发布时间】:2014-05-29 20:12:35
【问题描述】:

我想不通。为什么会这样编译:

typedef struct A {
    int foo[3];
} a_t;

typedef struct B {
    char tag;
    a_t foo;
} b_t;

const a_t default_a = { { 1, 2, 3 } };

int
main(int argc, char **argv)
{
    const b_t default_b = { 'A', default_a };
    return 0;
}

这不是:

typedef struct A {
    int foo[3];
} a_t;

typedef struct B {
    char tag;
    a_t foo;
} b_t;

const a_t default_a = { { 1, 2, 3 } };

const b_t default_b = { 'A', default_a };

int
main(int argc, char **argv)
{
    return 0;
}


> gcc tp.c
tp.c:13:1 error: initializer element is not constant
tp.c:31:1 error: (near initialization for ...default_b.foo...)

唯一的变化是 default_b 的声明范围。为什么这有什么不同?据我所知,它们要么都是有效的,要么都应该是错误的。但是 gcc (v4.7.3) 接受第一个而不是第二个。这让我发疯了。

[[edit]] 加分的后续问题:鉴于第二个程序不符合 C 标准,我该如何以符合标准的方式完成同样的事情? IE:default_b 的全局常量定义,包含 default_a 的值。

【问题讨论】:

    标签: c struct initialization


    【解决方案1】:

    C 语言规范要求使用常量表达式初始化具有静态存储持续时间的对象。

    在您的第一个代码段中,default_b 具有自动存储持续时间,而在第二个代码段中,它具有静态存储持续时间,因为它是在文件范围内定义的。所以第二个程序违反了规则:

    C11,6.7.9 初始化

    一个对象的初始化器中的所有表达式 线程存储持续时间应为常量表达式或字符串 文字。

    限定符const 确实不是 意味着它是一个常量表达式,而应该将其读取为只读。常量表达式是可以在编译时求值的东西:

    6.6 常量表达式

    可以在翻译过程中计算常量表达式,而不是 运行时,因此可以在常量可能的任何地方使用 是。

    【讨论】:

    • 嗯,就符合标准而言,这确实是有道理的。我明白为什么允许非常量表达式初始化器可能会出现问题。但是为什么它在第二种情况下起作用呢?在这两种情况下,编译器的知识状态不是完全相同吗?
    • 这不是编译器是否可以处理这样的初始化(理论上,编译器没有理由不能接受非常量表达式初始化器。)而是编译器只是遵循定义的语法和约束C语言。至于为什么是这样定义的,我没有任何答案:)
    • 原因是静态或线程存储持续时间对象的初始化程序通常由链接器/加载程序处理——可执行映像中有一个固定的字节块,当映像被“初始化”时加载。自动变量存储在堆栈中,它没有预定义的内容(它包含之前的堆栈帧),因此需要生成初始化 var 的实际存储指令并作为函数 prolog 的一部分运行,所以没有特别的需要涉及的值必须是常量表达式。
    • 这可能与效率有关(无需为初始化生成代码 - 编译时间更短,代码大小更小)。同样,我不知道在 C 中遵循这种语义背后的确切理由。这绝对与编译器生成代码的限制无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多