为什么 #pragma 一次不防范多个非 constexpr 定义?



刚刚花了一段时间调试多定义错误,但我不清楚为什么会发生这种行为,并希望了解。

我在头文件中有类似的东西。

//foo.h
#pragma once
my_states States[N] = {...};

后来,bar.h包括foo.h,因为bar.cpp具有需要了解my_states的功能。

当我为bar编写单元测试并将bar.h包含在test.cpp中时,出现了这个问题。

bar.o: multiple definition of MyNamespace::named_states
test.o: first defined here

我已经通过更改为

constexpr my_states States[n] = {...};foo.h.

但是我不明白为什么这会解决问题。我知道我对符号my_states有多个定义,这混淆了链接器,但是如果我有我的#pragma once保护,为什么多次定义?我不确定为什么我需要constexpr限定符来表示这应该只有 1 个定义,而据我所知,#pragma once应该首先阻止编译器尝试创建多个定义。

#pragma once只确保头文件只包含一次,它不处理代码。

关于my_states的第二个问题 - 在没有constexpr的情况下,您尝试定义一个可以在运行时修改的全局变量(或类似的东西(。通过在标头中设置其状态,您实际上可以使包含此头文件的每个库实例化并包含变量,而它应该是唯一定义的......基本上这是一个无法编译的完全混乱。您可以在头文件中声明静态/全局变量,但您应该在单个 cpp 文件中实例化它们。

通过在变量声明中添加constexpr,您可以向编译器传达它不能在运行时修改,此外,它的值在编译时是已知的。因此,无需担心哪个库存储/实例化它或类似的东西,因为它是编译时已知的绝对常量。

最新更新