使用其他常量结构实例初始化常量结构

12

我很好奇下面的代码片段为什么无法编译:

typedef struct Foo {
    int a;
    int b;
} Foo;

static const Foo FooZero = { 0, 0 };

typedef struct Bar {
    Foo foo;
    int c;
} Bar;

static const Bar BarZero = { FooZero, 0 };
它抱怨使用了FooZero,并说明FooZero不是编译时常量。但它不是吗?我在这里理解错了什么吗?显然,我可以简单地用{0,0} 替换初始化程序中的FooZero - 我提出问题的目的不是要解决问题,而是要尝试理解FooZero实际上为什么不是编译时常量的根本原因。谢谢

https://dev59.com/0HA75IYBdhLWcg3w790Y#3025106 是一个相当好的解释,概括了我要写的内容。 - Foo Bah
@Foo Bah - 感谢提供链接。然而,我的问题是“为什么会这样”。我觉得你引用的答案并没有真正回答我的“为什么”问题 - 它们只是指出了我已经知道的情况。 - Steve
@Steve 你在C语言中不能不使用函数吗?而且FooZero不是编译时常量。这就是两个链接都说的。 - Pavan Yalamanchili
@Pavan; “FooZero也不是编译时常量。” 是的,我知道。我的问题是为什么会这样?为什么语言机制会是这样的呢? - Steve
2个回答

13

主要与初始化有关。

通常情况下,变量的初始化不是由代码来指定具体的值,而是通过定义来加载特定值范围的 .data.rodata 段到内存位置上。这是由操作系统文件加载器完成的。(严格来说,这不是 C 的属性,C 不知道这些,其实是执行环境的属性。)

话虽如此,但是并不可能告诉程序将部分内存区域从另一个内存区域复制过来。但编译器本身可以识别声明的意图,并将相同的值放置到不同的位置。但那可能太过于“猜测”了。

在您的情况下:一个指向FooZero的指针可能是一个更好的解决方案吗?这两个值都是一样的...

typedef struct Foo {
    int a;
    int b;
} Foo;

static const Foo FooZero = { 0, 0 };

typedef struct Bar {
    Foo * foo;
    int c;
} Bar;

static const Bar BarZero = { &FooZero, 0 };

或者反过来:

typedef struct Foo {
    int a;
    int b;
} Foo;

typedef struct Bar {
    Foo foo;
    int c;
} Bar;

static const Bar BarZero = { { 0, 0 }, 0 };
static const Foo * FooZero = &BarZero.foo; // if that is possible, untested...
在第一种情况下,您需要使用->(如BarZero.foo->a)访问BarZero.foo的组件,
在第二种情况下,您需要使用->(如FooZero->a)访问FooZero的组件。

谢谢您对初始化的评论。这正是我在寻找的。关于指针的评论 - 我理解了 - 但是每次赋值时我需要整个结构体进行“复制”...因此,在这种情况下,拥有指向另一个结构体的指针并不是我想要的 - 如果某个地方有人改变了被指向的结构体中的值,它将破坏系统。但是,您的观点很好。谢谢! - Steve
1
由于它们都被声明为“const”,通常情况下不应该有人能够修改它。 - glglgl

2

在C语言中,conststatic const值并不被视为“编译时常量”,而是

#define FooZero  {0, 0}

被认为是编译时常量。你可能会说:“但是,它甚至标有const!它怎么可能不是常量?”事实上,语言规定您不能更改指定为const的值,但您也不能将其用作初始化器。您可以随意询问原因,但这并不会改变语言的定义 - 尽管编译器可能会给您提供更改此行为的选项,在任何情况下都不难解决。
我认为C编译器通常会像全局变量一样处理静态常量 - 也就是说,实际分配一个变量的空间(永远不会更改),而不是像使用#define一样将硬编码的值编入机器代码中。在这种情况下,常量确实如编译器所说的那样不是编译时常量,尽管它们在初始化后(在运行时)对于所有其他目的而言都是常量。

谢谢回复!---“你可以问为什么,但这不会改变语言的定义。”没错,但是我可能会从答案中受益。---“尽管它们在初始化后(在运行时)对于所有其他目的而言都是常量。”有趣。它们何时被初始化?第一次使用时吗?---此外,感谢您提供#define指针。 - Steve
@Steve 感谢您的评论 - 我认为glglgl对初始化的问题已经回答得很好了 - 初始化发生在启动程序时加载数据时。 - Brian L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接