当重构一些时,#defines
我遇到了类似于C++头文件中的以下声明:
static const unsigned int VAL = 42; const unsigned int ANOTHER_VAL = 37;
问题是,静态会产生什么不同,如果有的话?请注意,由于经典#ifndef HEADER
#define HEADER
#endif
技巧(如果重要),不可能多次包含标题.
VAL
如果标题包含在多个源文件中,静态是否只创建了一个副本?
文件范围变量上的static
和extern
标记确定它们是否可以在其他翻译单元(即其他.c
或.cpp
文件)中访问.
static
给出变量内部链接,将其隐藏在其他翻译单元之外.但是,具有内部链接的变量可以在多个翻译单元中定义.
extern
给出可变外部链接,使其对其他翻译单元可见.通常,这意味着变量必须仅在一个转换单元中定义.
默认值(当您未指定static
或时extern
)是C和C++不同的区域之一.
在C中,extern
默认情况下文件范围的变量是(外部链接).如果你使用C,VAL
是static
和ANOTHER_VAL
是extern
.
在C++中,static
默认情况下,文件范围的变量是(内部链接),如果是const
,则extern
默认情况下(如果不是).如果您使用C++,无论是VAL
和ANOTHER_VAL
是static
.
从C规范的草案:
6.2.2标识符的链接... -5-如果函数的标识符声明没有存储类说明符,则确定其链接与使用存储类说明符extern声明的链接完全相同.如果对象的标识符声明具有文件范围而没有存储类说明符,则其链接是外部的.
从C++规范的草案:
7.1.1 - 存储类说明符[dcl.stc] ... -6-在没有存储类说明符的命名空间作用域中声明的名称具有外部链接,除非由于先前的声明而具有内部链接且未提供声明const.声明为const且未显式声明为extern的对象具有内部链接.
这static
意味着将为其VAL
包含的每个源文件创建一个副本.但这也意味着多个包含将不会导致多个定义VAL
将在链接时发生冲突.在C中,没有static
你需要确保只有一个源文件定义,VAL
而其他源文件声明它extern
.通常可以通过在源文件中定义它(可能使用初始化程序)并将extern
声明放在头文件中来实现.
static
全局级别的变量只能在他们自己的源文件中看到,无论他们是通过包含还是在主文件中.
编者注:在C++中,声明中const
既static
没有extern
关键字也没有关键字的对象是隐含的static
.
静态意味着每个文件只能获得一个副本,但与其他人不同的是,这样做是完全合法的.您可以使用一个小代码示例轻松测试:
test.h:
static int TEST = 0; void test();
test1.cpp:
#include#include "test.h" int main(void) { std::cout << &TEST << std::endl; test(); }
测试2.cpp:
#include#include "test.h" void test() { std::cout << &TEST << std::endl; }
运行此命令可以获得此输出:
0x446020
0x446040
const
C++中的变量具有内部链接.所以,使用static
没有效果.
啊
const int i = 10;
one.cpp
#include "a.h" func() { cout << i; }
two.cpp
#include "a.h" func1() { cout << i; }
如果这是一个C程序,你会得到"多重定义"错误i
(由于外部链接).
此级别代码的静态声明意味着变量仅在当前编译单元中可见.这意味着只有该模块中的代码才能看到该变量.
如果您有一个声明变量static的头文件,并且该头包含在多个C/CPP文件中,那么该变量将对这些模块"本地".对于包含标题的N个位置,将有N个副本.他们完全没有关系.任何源文件中的任何代码都只引用该模块中声明的变量.
在这种特殊情况下,'static'关键字似乎没有提供任何好处.我可能会遗漏一些东西,但似乎并不重要 - 我以前从未见过这样的事情.
至于内联,在这种情况下变量很可能内联,但这只是因为它被声明为const.编译器可能更可能内联模块静态变量,但这取决于情况和正在编译的代码.无法保证编译器会内联"静态".