C++ 头文件中的变量声明 - 静态与否?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/92546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:47:40  来源:igfitidea点击:

Variable declarations in header files - static or not?

c++cstatic

提问by Rob

When refactoring away some #definesI came across declarations similar to the following in a C++ header file:

在重构一些时,#defines我在 C++ 头文件中遇到了类似于以下内容的声明:

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

The question is, what difference, if any, will the static make? Note that multiple inclusion of the headers isn't possible due to the classic #ifndef HEADER#define HEADER#endiftrick (if that matters).

问题是,如果有的话,静电会产生什么不同?请注意,由于经典#ifndef HEADER#define HEADER#endif技巧(如果这很重要),不可能包含多个标题。

Does the static mean only one copy of VALis created, in case the header is included by more than one source file?

VAL如果头文件包含在多个源文件中,静态是否意味着只创建一个副本?

回答by bk1e

The staticand externtags on file-scoped variables determine whether they are accessible in other translation units (i.e. other .cor .cppfiles).

文件范围变量上的staticextern标签决定了它们是否可以在其他翻译单元(即其他.c.cpp文件)中访问。

  • staticgives the variable internal linkage, hiding it from other translation units. However, variables with internal linkage can be defined in multiple translation units.

  • externgives the variable external linkage, making it visible to other translation units. Typically this means that the variable must only be defined in one translation unit.

  • static给出变量内部链接,对其他翻译单元隐藏它。但是,可以在多个翻译单元中定义具有内部链接的变量。

  • extern给出变量外部链接,使其对其他翻译单元可见。通常这意味着变量只能在一个翻译单元中定义。

The default (when you don't specify staticor extern) is one of those areas in which C and C++ differ.

默认值(当您未指定staticor 时extern)是 C 和 C++ 不同的领域之一。

  • In C, file-scoped variables are extern(external linkage) by default. If you're using C, VALis staticand ANOTHER_VALis extern.

  • In C++, file-scoped variables are static(internal linkage) by default if they are const, and externby default if they are not. If you're using C++, both VALand ANOTHER_VALare static.

  • 在 C 中,extern默认情况下文件范围的变量是(外部链接)。如果您使用 C,VAL则 isstaticANOTHER_VALis extern

  • 在C ++中,文件范围的变量是static(内部连接)默认如果它们const,并extern通过缺省,如果他们不。如果您使用的是 C++,则VALANOTHER_VAL都是static.

From a draft of the C specification:

来自C 规范的草案:

6.2.2 Linkages of identifiers ... -5- If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

6.2.2 标识符的链接... -5- 如果函数的标识符声明没有存储类说明符,则其链接的确定与使用存储类说明符 extern 声明的完全相同。如果对象的标识符声明具有文件范围且没有存储类说明符,则其链接是外部的。

From a draft of the C++ specification:

来自C++ 规范的草案:

7.1.1 - Storage class specifiers [dcl.stc] ... -6- A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared const. Objects declared const and not explicitly declared extern have internal linkage.

7.1.1 - 存储类说明符 [dcl.stc] ... -6- 在没有存储类说明符的命名空间范围内声明的名称具有外部链接,除非它由于先前的声明而具有内部链接并且提供它不是声明为常量。声明为 const 且未显式声明为 extern 的对象具有内部链接。

回答by Justsalt

The staticmeans that there will be one copy of VALcreated for each source file it is included in. But it also means that multiple inclusions will not result in multiple definitions of VALthat will collide at link time. In C, without the staticyou would need to ensure that only one source file defined VALwhile the other source files declared it extern. Usually one would do this by defining it (possibly with an initializer) in a source file and put the externdeclaration in a header file.

static意味着将为VAL包含它的每个源文件创建一个副本。但这也意味着多个包含不会导致多个定义VAL在链接时发生冲突。在 C 中,如果没有 ,static您将需要确保仅定义一个源文件VAL而其他源文件声明它extern。通常可以通过在源文件中定义它(可能使用初始值设定项)并将extern声明放在头文件中来做到这一点。

staticvariables at global level are only visible in their own source file whether they got there via an include or were in the main file.

static全局级别的变量仅在它们自己的源文件中可见,无论它们是通过包含还是在主文件中。



Editor's note:In C++, constobjects with neither the staticnor externkeywords in their declaration are implicitly static.

编者注:在 C++ 中,声明中const既没有 thestatic也没有extern关键字的对象是隐式的static

回答by slicedlime

The static will mean you get one copy per file, but unlike others have said it's perfectly legal to do so. You can easily test this with a small code sample:

静态意味着您每个文件都会获得一份副本,但与其他人所说的不同,这样做是完全合法的。您可以使用一个小代码示例轻松测试:

test.h:

测试.h:

static int TEST = 0;
void test();

test1.cpp:

测试1.cpp:

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp:

测试2.cpp:

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

Running this gives you this output:

运行它会给你这个输出:

0x446020
0x446040

0x446020
0x446040

回答by Nitin

constvariables in C++ have internal linkage. So, using statichas no effect.

constC++ 中的变量具有内部链接。所以,使用static没有效果。

a.h

const int i = 10;

one.cpp

一个.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

二.cpp

#include "a.h"

func1()
{
   cout << i;
}

If this were a C program, you would get 'multiple definition' error for i(due to external linkage).

如果这是一个 C 程序,您将收到“多重定义”错误i(由于外部链接)。

回答by Mark

The static declaration at this level of code means that the variabel is only visible in the current compilation unit. This means that only code within that module will see that variable.

此代码级别的静态声明意味着变量仅在当前编译单元中可见。这意味着只有该模块中的代码才能看到该变量。

if you have a header file that declares a variable static and that header is included in multiple C/CPP files, then that variable will be "local" to those modules. There will be N copies of that variable for the N places that header is included. They are not related to each other at all. Any code within any of those source files will only reference the variable that is declared within that module.

如果您有一个声明变量 static 的头文件,并且该头文件包含在多个 C/CPP 文件中,那么该变量将是这些模块的“本地”变量。对于包含标头的 N 个位置,将有该变量的 N 个副本。它们彼此之间根本没有关系。任何这些源文件中的任何代码都将只引用在该模块中声明的变量。

In this particular case, the 'static' keyword doesn't seem to be providing any benefit. I might be missing something, but it seems to not matter -- I've never seen anything done like this before.

在这种特殊情况下,“static”关键字似乎没有提供任何好处。我可能会遗漏一些东西,但这似乎无关紧要——我以前从未见过这样的事情。

As for inlining, in this case the variable is likely inlined, but that's only because it's declared const. The compiler mightbe more likely to inline module static variables, but that's dependent on the situation and the code being compiled. There is no guarantee that the compiler will inline 'statics'.

至于内联,在这种情况下,变量可能是内联的,但这只是因为它被声明为 const。编译器可能更有可能内联模块静态变量,但这取决于情况和正在编译的代码。不能保证编译器会内联“静态”。

回答by Jan de Vos

The C book (free online) has a chapter about linkage, which explains the meaning of 'static' in more detail (although the correct answer is already given in other comments): http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html

C 书(免费在线)有一章关于链接,它更详细地解释了“静态”的含义(尽管其他评论中已经给出了正确答案):http: //publications.gbdirect.co.uk/c_book /chapter4/linkage.html

回答by itj

To answer the question, "does the static mean only one copy of VAL is created, in case the header is included by more than one source file?"...

要回答这个问题,“静态是否意味着只创建一个 VAL 副本,以防头文件包含在多个源文件中?”...

NO. VAL will always be defined separately in every file that includes the header.

。VAL 将始终在包含标题的每个文件中单独定义。

The standards for C and C++ do cause a difference in this case.

在这种情况下,C 和 C++ 的标准确实会导致差异。

In C, file-scoped variables are extern by default. If you're using C, VAL is static and ANOTHER_VAL is extern.

在 C 中,文件范围的变量默认为 extern。如果您使用 C,则 VAL 是静态的,而 ANOTHER_VAL 是外部的。

Note that Modern linkers may complain about ANOTHER_VAL if the header is included in different files (same global name defined twice), and would definitely complain if ANOTHER_VAL was initialised to a different value in another file

请注意,如果标头包含在不同的文件中(定义了两次相同的全局名称),现代链接器可能会抱怨 ANOTHER_VAL,并且如果 ANOTHER_VAL 在另一个文件中初始化为不同的值,则肯定会抱怨

In C++, file-scoped variables are static by default if they are const, and extern by default if they are not. If you're using C++, both VAL and ANOTHER_VAL are static.

在 C++ 中,如果文件范围的变量是 const,则默认情况下是静态的,如果不是,则默认情况下是 extern。如果您使用 C++,则 VAL 和 ANOTHER_VAL 都是静态的。

You also need to take account of the fact that both variables are designated const. Ideally the compiler would always choose to inline these variables and not include any storage for them. There is a whole host of reasons why storage can be allocated. Ones I can think of...

您还需要考虑到两个变量都被指定为 const 的事实。理想情况下,编译器将始终选择内联这些变量,而不为它们包含任何存储空间。可以分配存储的原因有很多。我能想到的...

  • debug options
  • address taken in the file
  • compiler always allocates storage (complex const types can't easily be inlined, so becomes a special case for basic types)
  • 调试选项
  • 文件中的地址
  • 编译器总是分配存储空间(复杂的 const 类型不能轻易内联,因此成为基本类型的特例)

回答by Gajendra Kumar

You can't declare a static variable without defining it as well (this is because the storage class modifiers static and extern are mutually exclusive). A static variable can be defined in a header file, but this would cause each source file that included the header file to have its own private copy of the variable, which is probably not what was intended.

您不能在不定义静态变量的情况下声明它(这是因为存储类修饰符 static 和 extern 是互斥的)。可以在头文件中定义静态变量,但这会导致包含头文件的每个源文件都有自己的变量私有副本,这可能不是预期的。

回答by bruziuz

constvariables are by default static in C++, but extern C. So if you use C++ this no sense what construction to use.

const变量在 C++ 中默认是静态的,但在 C 中是 extern。所以如果你使用 C++,这没有意义使用什么构造。

(7.11.6 C++ 2003, and Apexndix C has samples)

(7.11.6 C++ 2003,Apexndix C 有示例)

Example in compare compile/link sources as C and C++ program:

将编译/链接源作为 C 和 C++ 程序进行比较的示例:

bruziuz:~/test$ cat a.c
const int b = 22;
int main(){return 0;}
bruziuz:~/test$ cat b.c
const int b=2;
bruziuz:~/test$ gcc -x c -std=c89 a.c b.c
/tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b'
/tmp/ccDSd0V3.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c 
bruziuz:~/test$ 
bruziuz:~/test$ gcc --version | head -n1
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609

回答by Seb Rose

Assuming that these declarations are at global scope (i.e. aren't member variables), then:

假设这些声明在全局范围内(即不是成员变量),那么:

staticmeans 'internal linkage'. In this case, since it is declared constthis can be optimised/inlined by the compiler. If you omit the constthen the compiler must allocate storage in each compilation unit.

静态意味着“内部链接”。在这种情况下,由于它被声明为const,因此编译器可以对其进行优化/内联。如果省略const,则编译器必须在每个编译单元中分配存储空间。

By omitting staticthe linkage is externby default. Again, you've been saved by the constness - the compiler can optimise/inline usage. If you drop the constthen you will get a multiply defined symbolserror at link time.

通过省略static链接默认为extern。同样,您已经被const性拯救了- 编译器可以优化/内联使用。如果您删除const,那么您将在链接时收到多重定义的符号错误。