头文件中的“静态”、“外部”、“常量”

`static`, `extern`, `const` in header file

本文关键字:外部 常量 文件 静态      更新时间:2023-10-16
//a.h
extern int x1;
static int x2;
int x3;
static const int x4;
class A {
    public:
        static const int x5 = 10;
};

a.h将被多个.cpp文件包含,我的问题是:

1. x1只是一个宣言,不是吗?所以它的定义应该在其中一个.cpp文件中完成,对吧?

2. x2是一个定义,对吧?我曾经认为static intextern int一样也是一个宣言,但我错了。 x2只会在a.h中可见?

3. 如果a.h包含在多个.cpp文件中,x3将被多次定义,因此x3会导致编译错误,对吗?

4. x4是一个定义,对吧?

5.在A类中,x5是一个声明,是的。但是x4呢?

1.x1只是一个声明,不是吗?所以它的定义应该在其中一个.cpp文件中完成,对吧?

正确

2.x2是一个定义,对吧?我曾经认为静态 int 也是一个声明,就像 extern int 一样,但我错了。X2 只会在 A.H 中可见?

包含标题的每个翻译单元中将提供不同的x2

如果 a.h 包含在多个.cpp文件中,3.x3 将被多次定义,所以 x3 会导致编译错误,对吧?

更准确地说,它会导致链接器错误。编译器处理每个翻译单元,链接器将它们绑定在一起,并检测符号被多次定义。

4.x4是一个定义,对吧?

是的,这是一个定义,但与x2一样,每个翻译单元都有自己的x4(既是因为static,也是因为它const这意味着内部联系。

5.在A类中,x5是声明,是的。但是x4呢?

是的,x5只是一个声明(带有初始化(。可能会出现混淆,因为关键字static在不同的上下文中被重用于表示不同的东西。在x5中它表示类的属性,而在x4中它表示内部链接

最后一种情况很特殊。它是声明可以具有值的唯一声明 (IIRC(,原因是它允许编译器在包含该标头的所有翻译单元中使用该常量的值作为编译时常量。如果必须随定义一起提供该值,则只有一个翻译单元可以访问该值。该静态成员的定义是:

const int A::x5; // no initialization here

如果成员是使用 odr 的,则必须提供一个。现在的事实是,在大多数情况下,常量不会被 odr 使用,因为编译器会在使用表达式 A::x5 时替换该值。仅当成员用作左值时,您才需要定义,例如:

void f( const int & ) {}
int main() {
   f( A::x5 );
}

由于 f 的参数是引用,因此使用 A::x5 需要一个左值(注意,常量和左值/右几乎是正交的(,这需要在程序中的单个翻译单元中定义成员。

  1. 正确

  2. 它是一个定义,x2将为 0,并且包含标头的每个翻译单元都有自己的 x2 副本。

  3. 是的,但它会导致链接器错误,而不是编译器。

  4. 与 2. 相同,但您无法修改它。

  5. 在类内部,static具有不同的含义。在那里是合法的x5,因为它是常量整数类型,也已初始化。