我希望你们中的一个人能够向我解释为什么编译器要求我在编译单元中重新定义了一个静态的固定长度数组,尽管在标题中已经这样做了。这是一个例子:
MyClass.h:
#ifndef MYCLASS_H
#define MYCLASS_H
class MyClass {
private:
static char myPrecomputeTable[256];
}
#endif
MyClass.cpp
#include "MyClass.h"
char MyClass::myPrecomputeTable[256];
如果我删除MyClass.cpp中的重新定义,链接器会抱怨myPrecomputeTable未定义。语法似乎多余。任何人都可以向我解释为什么编译器/链接器需要定义吗?
编辑:
对不起,我想我不清楚我对此感到困惑。我理解声明/定义概念,它更像是我觉得有趣的数组大小的定义。在定义和声明中,我必须定义看似多余的大小。
编辑:
我做了一些挖掘,结果发现这个主题的一些方法是编译友好的。 编译:
MyClass.h
class MyClass {
static char myPrecomputeTable[256];
};
MyClass.cpp
char MyClass::myPrecomputeTable[256];
编译:
MyClass.h
class MyClass {
static char myPrecomputeTable[];
};
MyClass.cpp
char MyClass::myPrecomputeTable[256];
编译:
MyClass.h
class MyClass {
static char myPrecomputeTable[256];
};
MyClass.cpp
char MyClass::myPrecomputeTable[];
不编译:
MyClass.h
class MyClass {
static char myPrecomputeTable[512];
};
MyClass.cpp
char MyClass::myPrecomputeTable[256];
大小必须在标题或类中或两者中定义,但编译器足够智能以阻止大小冲突。
答案 0 :(得分:6)
在标题中:
class MyClass {
private:
static char myPrecomputeTable[256];
}
这是声明。
在.cpp:
char MyClass::myPrecomputeTable[256];
是定义。
声明提供符号的基本属性:其类型和名称。
定义提供该符号的所有细节 - 如果它是一个函数,它的作用是什么;如果它是一个类,它有哪些领域和方法;如果它是一个变量,那么存储该变量。
通常,编译器只需要声明一些东西,以便将文件编译成目标文件,期望链接器可以从另一个文件中找到定义。如果源文件没有定义符号,但是声明了它,那么在链接时会出现错误,抱怨未定义的符号。
了解两者之间差异的良好链接:http://www.cprogramming.com/declare_vs_define.html
来自标准:
3.1声明和定义[basic.def]
声明可能会将一个或多个名称引入翻译单元或重新声明先前声明引入的名称。如果是,则声明指定这些名称的解释和属性。声明也可能具有以下效果:
- 静态断言(第7条),
- 控制模板实例化(14.7.2),
- 使用属性(第7条)和
- 没有(在空声明的情况下)。
- 醇>
声明是定义,除非它声明了一个函数而没有指定函数的主体,它包含
extern
说明符或 linkage-specification 既不是初始值设定项也不是函数体,它在类定义中声明了一个静态数据成员,它是一个类名声明,它是 opaque-enum-declaration ,或者是 typedef声明, using-declaration ,static_assert-declaration,属性声明,空声明或 using-directive 。
答案 1 :(得分:2)
头文件中的第一个只是一个声明,告诉编译器该成员存在于包含头文件的所有其他源文件。
源文件中的第二个是实际的定义,当将整个项目链接到一个可执行文件时,链接器需要它。
在必须告诉编译器两次大小的情况下,这就是指定语言的工作方式。你(或任何人)对此无能为力。
但是,您可以使用typedef
解决此问题:
class MyClass
{
typedef char PrecomputeTable_t[256];
static PrecomputeTable_t myPrecomputeTable;
};
...
MyClass::PrecomputeTable_t MyClass::myPrecomputeTable;