C++ 为什么重新定义一个固定大小的静态阵列是必需的/有效的?

C++ 为什么重新定义一个固定大小的静态阵列是必需的/有效的?,c++,C++,我希望你们中的一位能够向我解释为什么编译器要求我在编译单元中重新定义静态固定长度数组,尽管我已经在头中这样做了。下面是一个例子: MyClass.h: #ifndef MYCLASS_H #define MYCLASS_H class MyClass { private: static char myPrecomputeTable[256]; } #endif MyClass.cpp #include "MyClass.h" char MyClass::myPrecomputeT

我希望你们中的一位能够向我解释为什么编译器要求我在编译单元中重新定义静态固定长度数组,尽管我已经在头中这样做了。下面是一个例子:

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中的重新定义,链接器会抱怨MyPreComputerTable未定义。语法似乎是多余的。有人能给我解释一下为什么编译器/链接器需要这个定义吗

编辑:

对不起,我想我不清楚我到底在想什么。我理解声明/定义的概念,我更感兴趣的是定义数组的大小。在定义和声明中,我必须定义看起来多余的大小

编辑:

我做了更多的挖掘工作,结果证明,这个主题的许多方法都是对编译器友好的。 汇编:

MyClass.h
class MyClass {
    static char myPrecomputeTable[256];
};

MyClass.cpp
char MyClass::myPrecomputeTable[256];
汇编:

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[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];

必须在头文件或类或两者中定义大小,但编译器足够聪明,可以停止大小冲突。

头文件中的第一个只是一个声明,告诉编译器包含头文件的所有其他源文件都存在此成员

源文件中的第二个是实际定义,链接器在将整个项目链接到单个可执行文件中时需要它


在必须告诉编译器两次大小的情况下,这就是指定语言工作的方式。你(或任何人)对此无能为力

但是,您可以使用
typedef
解决此问题:

class MyClass
{
    typedef char PrecomputeTable_t[256];

    static PrecomputeTable_t myPrecomputeTable;
};

...

MyClass::PrecomputeTable_t MyClass::myPrecomputeTable;

头文件中的第一个只是一个声明,告诉编译器包含头文件的所有其他源文件都存在该成员

源文件中的第二个是实际定义,链接器在将整个项目链接到单个可执行文件中时需要它


在必须告诉编译器两次大小的情况下,这就是指定语言工作的方式。你(或任何人)对此无能为力

但是,您可以使用
typedef
解决此问题:

class MyClass
{
    typedef char PrecomputeTable_t[256];

    static PrecomputeTable_t myPrecomputeTable;
};

...

MyClass::PrecomputeTable_t MyClass::myPrecomputeTable;
在标题中:

class MyClass {
private:
    static char myPrecomputeTable[256];
}
这是一个声明

在.cpp中:

char MyClass::myPrecomputeTable[256];
是一个定义

声明提供符号的基本属性:类型和名称

定义提供了该符号的所有细节——如果它是一个函数,它的作用是什么;如果它是一个类,它有哪些字段和方法;如果它是一个变量,那么该变量存储在哪里

通常,为了将文件编译成目标文件,编译器只需要对某些内容进行声明,这样链接器就可以从另一个文件中找到定义。如果没有任何源文件定义符号,但它已声明,则在链接时会出现错误,抱怨未定义的符号

了解两者之间差异的一个好链接:


根据标准:

3.1声明和定义[basic.def]

  • 声明可以将一个或多个名称引入翻译单元,也可以重新声明以前声明引入的名称。如果是,声明将指定这些名称的解释和属性。声明也可能具有以下影响:

    • 静态断言(第7条)
    • 控制模板实例化(14.7.2)
    • 属性的使用(第7条),以及
    • 无(在空声明的情况下)
  • 声明是一个定义,除非它在声明函数时没有指定函数体,它包含
    extern
    说明符或链接规范,既不是初始值设定项也不是函数体,它在类定义中声明静态数据成员,它是一个类名声明,它是不透明的枚举声明,或者是typedef声明、using声明、static_assert-declaration、attribute声明、空声明或using指令

  • 在标题中:

    class MyClass {
    private:
        static char myPrecomputeTable[256];
    }
    
    这是一个声明

    在.cpp中:

    char MyClass::myPrecomputeTable[256];
    
    是一个定义

    声明提供符号的基本属性:类型和名称

    定义提供了该符号的所有细节——如果它是一个函数,它的作用是什么;如果它是一个类,它有哪些字段和方法;如果它是一个变量,那么该变量存储在哪里

    通常,为了将文件编译成目标文件,编译器只需要对某些内容进行声明,这样链接器就可以从另一个文件中找到定义。如果没有任何源文件定义符号,但它已声明,则在链接时会出现错误,抱怨未定义的符号

    了解两者之间差异的一个好链接:


    根据标准:

    3.1声明和定义[basic.def]

  • 声明可以将一个或多个名称引入翻译单元,也可以重新声明以前声明引入的名称。如果是,声明将指定这些名称的解释和属性。声明也可能具有以下影响:

    • 静态断言(第7条)
    • 控制模板实例化(14.7.2)
    • 属性的使用(第7条),以及
    • 无(在空声明的情况下)
  • 声明是一个定义,除非它声明函数而不指定函数体,它包含
    extern
    说明符或链接规范,既不是初始值设定项也不是函数体,它在类定义中声明静态数据成员,它是类名声明,它是