在C和C ++中,“const static”是什么意思?
const static int foo = 42;
我在StackOverflow的一些代码中看到了这一点,我无法弄清楚它在做什么。 然后我在其他论坛上看到一些混淆的答案。 我最好的猜测是它在C中用来隐藏其他模块的常量foo
。 它是否正确? 如果是这样,为什么任何人都可以在C ++上下文中使用它,你可以把它变成private
?
它在C和C ++中都有使用。
正如你猜测的那样, static
部分将其范围限制在编译单元中 。 它也提供了静态初始化。 const
只是告诉编译器不要让任何人修改它。 这个variables要么根据体系结构放在数据段中,要么放在内存中标记为只读。
所有这些都是C如何处理这些variables(或者C ++如何处理命名空间variables)。 在C ++中,标记为static
的成员由给定类的所有实例共享。 无论是否私有都不会影响一个variables被多个实例共享的事实。 如果有任何代码会尝试修改,那么在那里有const
会警告你。
如果它是严格私有的,那么每个类的实例都会得到它自己的版本(优化器尽pipe)。
很多人都给出了基本的答案,但没有人指出,在C ++中, const
在namespace
级别默认为static
(有些给出了错误的信息)。 请参阅C ++ 98标准部分3.5.3。
首先是一些背景:
翻译单元:预处理器(recursion)之后的源文件包括其所有包含文件。
静态链接:符号仅在其翻译单元中可用。
外部链接:其他翻译单元提供了一个符号。
在namespace
级别
这包括全局名称空间又名全局variables 。
static const int sci = 0; // sci is explicitly static const int ci = 1; // ci is implicitly static extern const int eci = 2; // eci is explicitly extern extern int ei = 3; // ei is explicitly extern int i = 4; // i is implicitly extern static int si = 5; // si is explicitly static
在function级别
static
意味着函数调用之间的值保持不变。
函数static
variables的语义类似于全局variables,因为它们驻留在程序的数据段 (而不是堆栈或堆)中,请参阅此问题以获取有关static
variables生命周期的更多详细信息。
在class
上
static
意味着该值在类的所有实例之间共享,并且const
意味着它不会改变。
这行代码实际上可能出现在几个不同的上下文中,并且它们的行为大致相同,但有一些细微的差别。
命名空间范围
// foo.h static const int i = 0;
包含标题的每个翻译单元中都会显示“ i
”。 但是,除非实际使用对象的地址(例如' &i
'),否则我很确定编译器将“ i
”视为types安全0
。 如果再有两个翻译单元采用“ &i
”,则每个翻译单元的地址将会不同。
// foo.cc static const int i = 0;
' i
'有内部联系,所以不能从这个翻译单位以外引用。 但是,除非你使用地址,否则它很可能被视为types安全的0
。
值得指出的一点是,下面的声明是:
const int i1 = 0;
与static const int i = 0
完全一样。 用const
声明的一个名字空间中的variables并没有用extern
显式声明,而是隐含的静态的。 如果你想到这一点,C ++委员会的目的是允许在头文件中声明const
variables,而不需要static
关键字来避免破坏ODR。
class级范围
class A { public: static const int i = 0; };
在上面的例子中,标准明确规定如果地址不是必需的,“ i
”不需要定义。 换句话说,如果只使用' i
'作为types安全的0,那么编译器将不会定义它。 类和名称空间版本之间的一个区别是“ i
”(如果在两个或更多的翻译单元中使用)的地址对于类成员将是相同的。 在使用地址的地方,你必须有一个定义:
// ah class A { public: static const int i = 0; }; // a.cc #include "ah" const int A::i; // Definition so that we can take the address
这是一个小空间优化。
当你说
const int foo = 42;
你没有定义一个常量,而是创build一个只读variables。 编译器足够聪明,只要看到foo就可以使用它,但是它也会在初始化的数据区域中为它分配空间。 这样做是因为,如所定义的,foo具有外部链接。 另一个汇编单位可以这样说:
extern const int foo;
获取其价值。 这不是一个好的做法,因为编制单位不知道foo的价值是什么。 它只知道它是一个const int,只要使用它就必须从内存中重新加载值。
现在,声明它是静态的:
static const int foo = 42;
编译器可以进行通常的优化,但是也可以说“嘿,这个编译单元之外没有人能看到foo,我知道它总是42,所以不需要为它分配任何空间”。
我还应该注意,在C ++中,防止从当前编译单元转义名称的首选方法是使用匿名名称空间:
namespace { const int foo = 42; // same as static definition above }
它缺less一个'int'。 它应该是:
const static int foo = 42;
在C和C ++中,它声明一个整型常量,其值为42。
为什么42? 如果你还不知道(很难相信你不知道),那就是对生命的回应,宇宙和万物的回应 。
在C ++中,
static const int foo = 42;
是定义和使用常量的首选方法。 即使用这个而不是
#define foo 42
因为它不会颠覆型号安全系统。
这是全局常量只有在编译模块(.cpp文件)中才可见/可访问。 BTW使用静态为此目的已被弃用。 更好地使用匿名命名空间和枚举:
namespace { enum { foo = 42 }; }
所有的好的答案,我想添加一个小细节:
如果您编写插件(例如,由CAD系统加载的DLL或.so库),那么static就是一个避免名称冲突的生命保护程序,如下所示:
- CAD系统加载一个插件A,它有一个“const int foo = 42;” 在里面。
- 系统加载一个插件B,其中包含“const int foo = 23;” 在里面。
- 结果,插件B将为foo使用值42,因为插件加载器会意识到,已经有一个具有外部链接的“foo”。
更糟糕的是:根据编译器优化,插件加载机制等,第3步可能会有所不同。
我有两个插件中的两个辅助函数(相同的名称,不同的行为)曾经有过这个问题。 宣布他们静态解决了这个问题。
是的,它从其他模块隐藏了一个模块的variables。 在C ++中,当我不需要/需要更改一个会触发不必要的重build其他文件的.h文件时,我会使用它。 另外,我把静态的第一:
static const int foo = 42;
而且,根据它的用途,编译器甚至不会为它分配存储空间,只是“内联”它所使用的值。 如果没有静态的,编译器不能假定它没有在其他地方使用,也不能内联。
使其保持私密仍然意味着它出现在标题中。 我倾向于使用“最弱”的方式。 请参阅Scott Meyers的这篇经典文章: http : //www.ddj.com/cpp/184401197 (这是关于函数,但也可以在这里应用)。
根据C99 / GNU99规范:
-
static
-
是存储类说明符
-
文件级作用域的对象默认具有外部连接
- 具有静态说明符的文件级范围的对象具有内部链接
-
-
const
-
是types限定符(是types的一部分)
-
关键字应用到即时左侧实例 – 即
-
MyObj const * myVar;
– 不合格的指向const限定对象types的指针 -
MyObj * const myVar;
– const限定指向非限定对象types的指针
-
-
最左边的用法 – 应用于对象types,不可变
-
const MyObj * myVar;
– 不合格的指向const限定对象types的指针
-
-
从而:
static NSString * const myVar;
– 不变的指向内部连接的不可变string的指针。
缺lessstatic
关键字将使全局variables名称可能导致应用程序中的名称冲突。