Ste*_*eve 10 c++ linker-warning
我在标题中定义了一个字符数组
//header.h
const char* temp[] = {"JeffSter"};
Run Code Online (Sandbox Code Playgroud)
如果#defined受到保护,则标题在顶部有一次#pragma.如果这个头包含在多个地方,我得到一个LNK4006 - 已经在blahblah.obj中定义的char const**temp.所以,我有几个问题
Alo*_*hal 14
如果我有防护装置,为什么会发生这种情况?我认为他们阻止了首次访问后读取标头.
包含警卫确保标题仅包含在一个文件(翻译单元)中一次.对于包含标题的多个文件,您希望标题包含在每个文件中.
通过定义,而不是在头文件中使用外部链接(全局变量)声明变量,您只能在一次源文件中包含标头.如果在多个源文件中包含标头,则会有多个变量定义,这在C++中是不允许的.
因此,正如您所知,在头文件中定义变量是一个坏主意,正是出于上述原因.
为什么此标题中的众多枚举还没有给出LNK4006警告?
因为,它们没有定义"全局变量",它们只是关于类型等的声明.它们不保留任何存储空间.
如果我在签名前添加静态,我不会收到警告.这样做有什么意义呢.
创建变量时static
,它具有静态范围.该对象在定义它的转换单元(文件)之外是不可见的.所以,简单来说,如果你有:
static int i;
Run Code Online (Sandbox Code Playgroud)
在标题中,包含标题的每个源文件都将获得一个单独的 int
变量i
,该变量在源文件之外是不可见的.这被称为内部联系.
有没有更好的方法来避免错误,但让我在标题中声明数组.我真的很讨厌只有一个cpp文件用于数组定义.
如果您希望数组是所有C++文件中可见的一个对象,您应该:
extern int array[SIZE];
Run Code Online (Sandbox Code Playgroud)
在头文件中,然后在所有需要该变量的C++源文件中包含头文件array
.在其中一个 source(.cpp
)文件中,您需要定义array
:
int array[SIZE];
Run Code Online (Sandbox Code Playgroud)
您还应该在上面的源文件中包含标题,以允许捕获由于标头和源文件的差异而导致的错误.
基本上,extern
告诉编译器" array
在某处定义,并具有类型int
和大小SIZE
".然后,您实际上只定义 array
一次.在链接阶段,一切都很好地解决了.
包含防护可以防止您将相同的标头重复包含到同一个文件中,但不能将其包含到不同的文件中。
发生的情况是链接器看到temp
多个目标文件 - 您可以通过将其设置为temp
静态或将其放入未命名的命名空间来解决此问题:
static const char* temp1[] = {"JeffSter"};
// or
namespace {
const char* temp2[] = {"JeffSter"};
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用一个源文件来定义temp
并在标头中将其声明为 extern:
// temp.cpp:
const char* temp[] = {"JeffSter"};
// header.h:
extern const char* temp[];
Run Code Online (Sandbox Code Playgroud)
标题保护与防止整个程序中的多个定义完全无关。头保护的目的是防止将同一头文件多次包含到同一翻译单元(.cpp 文件)中。换句话说,它们的存在是为了防止在同一个源文件中有多个定义。在您的情况下,它们确实按预期工作。
在 C++ 中管理多重定义问题的规则称为单一定义规则 (ODR)。对于不同类型的实体,ODR 的定义不同。例如,允许类型在程序中具有多个相同的定义。它们可以(并且大多数情况下必须)在使用它们的每个翻译单元中定义。这就是为什么您的枚举定义不会导致错误的原因。
具有外部链接的对象是一个完全不同的故事。它们必须在一个且仅一个翻译单元中定义。这就是temp
当您将头文件包含到多个翻译单元时,您的定义会导致错误的原因。包含警卫无法防止此错误。只是不要在头文件中定义具有外部链接的对象。
通过添加static
你给你的对象内部链接。这将使错误消失,因为现在从 ODR 的角度来看完全没问题。但这将temp
在包含您的头文件的每个翻译单元中定义一个独立的对象。为了达到同样的效果,你也可以这样做
const char* const temp[] = { "JeffSter" };
Run Code Online (Sandbox Code Playgroud)
因为const
C++ 中的对象默认具有内部链接。
这取决于您是需要一个带有外部链接的对象(即一个用于整个程序的对象)还是一个带有内部链接的对象(每个翻译单元唯一的)。如果您需要后者,请使用static
和/或额外const
(如果这对您有用),如上所示。
如果需要前者(外部链接),则应在头文件中放入一个非定义声明
extern const char* temp[];
Run Code Online (Sandbox Code Playgroud)
并将定义移动到一个且仅一个 .cpp 文件中
char* const temp[] = { "JeffSter" };
Run Code Online (Sandbox Code Playgroud)
头文件中的上述声明适用于大多数目的。然而,它声明temp
为一个未知大小的数组——一个不完整的类型。如果您希望将其声明为已知大小的数组,则必须手动指定大小
extern const char* temp[1];
Run Code Online (Sandbox Code Playgroud)
并记住在声明和定义之间保持同步。
归档时间: |
|
查看次数: |
5808 次 |
最近记录: |