C 和 C++ 中的“const static”是什么意思?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/177437/
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 13:27:27  来源:igfitidea点击:

What does 'const static' mean in C and C++?

c++c

提问by c0m4

const static int foo = 42;

I saw this in some code here on StackOverflow and I couldn't figure out what it does. Then I saw some confused answers on other forums. My best guess is that it's used in C to hide the constant foofrom other modules. Is this correct? If so, why would anyone use it in a C++ context where you can just make it private?

我在 StackOverflow 上的一些代码中看到了这一点,但我无法弄清楚它的作用。然后我在其他论坛上看到了一些混乱的答案。我最好的猜测是它在 C 中用于对foo其他模块隐藏常量。这样对吗?如果是这样,为什么有人会在 C++ 上下文中使用它,您可以在其中制作它private

采纳答案by Chris Arguin

It has uses in both C and C++.

它在 C 和 C++ 中都有使用。

As you guessed, the staticpart limits its scope to that compilation unit. It also provides for static initialization. constjust tells the compiler to not let anybody modify it. This variable is either put in the data or bss segment depending on the architecture, and might be in memory marked read-only.

如您所料,该static部分将其范围限制为该编译单元。它还提供静态初始化。const只是告诉编译器不要让任何人修改它。该变量根据架构放置在 data 或 bss 段中,并且可能在标记为只读的内存中。

All that is how C treats these variables (or how C++ treats namespace variables). In C++, a member marked staticis shared by all instances of a given class. Whether it's private or not doesn't affect the fact that one variable is shared by multiple instances. Having conston there will warn you if any code would try to modify that.

这就是 C 如何处理这些变量(或 C++ 如何处理命名空间变量)。在 C++ 中,标记的成员static由给定类的所有实例共享。是否私有并不影响一个变量被多个实例共享这一事实。如果const有任何代码试图修改它,在那里会警告你。

If it was strictly private, then each instance of the class would get its own version (optimizer notwithstanding).

如果它是严格私有的,那么该类的每个实例都会有自己的版本(尽管有优化器)。

回答by Motti

A lot of people gave the basic answer but nobody pointed out that in C++ constdefaults to staticat namespacelevel (and some gave wrong information). See the C++98 standard section 3.5.3.

很多人给出了基本答案,但没有人指出,在C ++中const默认staticnamespace水平(有的给出了错误信息)。请参阅 C++98 标准第 3.5.3 节。

First some background:

首先介绍一下背景:

Translation unit:A source file after the pre-processor (recursively) included all its include files.

翻译单元:预处理器(递归地)包含其所有包含文件之后的源文件。

Static linkage:A symbol is only available within its translation unit.

静态链接:符号仅在其翻译单元内可用。

External linkage:A symbol is available from other translation units.

外部链接:符号可从其他翻译单元获得。

At namespacelevel

namespace水平

This includes the global namespace aka global 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

At function level

在功能层面

staticmeans the value is maintained between function calls.
The semantics of function staticvariables is similar to global variables in that they reside in the program's data-segment(and not the stack or the heap), see this questionfor more details about staticvariables' lifetime.

static意味着该值在函数调用之间保持不变。
函数static变量的语义类似于全局变量,因为它们驻留在程序的数据段(而不是堆栈或堆)中,有关变量生命周期的更多详细信息,请参阅此问题static

At classlevel

class水平

staticmeans the value is shared between all instances of the class and constmeans it doesn't change.

static意味着该值在类的所有实例之间共享,并且const意味着它不会改变。

回答by Richard Corden

That line of code can actually appear in several different contexts and alghough it behaves approximately the same, there are small differences.

这行代码实际上可以出现在几个不同的上下文中,尽管它的行为大致相同,但还是有细微的差别。

Namespace Scope

命名空间范围

// foo.h
static const int i = 0;

'i' will be visible in every translation unit that includes the header. However, unless you actually use the address of the object (for example. '&i'), I'm pretty sure that the compiler will treat 'i' simply as a type safe 0. Where two more more translation units take the '&i' then the address will be different for each translation unit.

i”将在包含标题的每个翻译单元中可见。但是,除非您实际使用对象的地址(例如。' &i'),我很确定编译器会将 ' i' 简单地视为类型安全0。如果另外两个翻译单元采用“ &i”,则每个翻译单元的地址将不同。

// foo.cc
static const int i = 0;

'i' has internal linkage, and so cannot be referred to from outside of this translation unit. However, again unless you use its address it will most likely be treated as a type-safe 0.

i”具有内部链接,因此不能从该翻译单元外部引用。但是,除非您使用它的地址,否则它很可能会被视为类型安全的0

One thing worth pointing out, is that the following declaration:

值得指出的一件事是以下声明:

const int i1 = 0;

is exactlythe same as static const int i = 0. A variable in a namespace declared with constand not explicitly declared with externis implicitly static. If you think about this, it was the intention of the C++ committee to allow constvariables to be declared in header files without always needing the statickeyword to avoid breaking the ODR.

完全相同一样static const int i = 0。命名空间中声明的变量const和未显式声明的变量extern是隐式静态的。如果您考虑一下,C++ 委员会的意图是允许const在头文件中声明变量而不总是需要static关键字以避免破坏 ODR。

Class Scope

类范围

class A {
public:
  static const int i = 0;
};

In the above example, the standard explicitly specifies that 'i' does not need to be defined if its address is not required. In other words if you only use 'i' as a type-safe 0 then the compiler will not define it. One difference between the class and namespace versions is that the address of 'i' (if used in two ore more translation units) will be the same for the class member. Where the address is used, you must have a definition for it:

在上面的示例中,标准明确指定i如果不需要其地址,则不需要定义“ ”。换句话说,如果您只使用 ' i' 作为类型安全的 0,那么编译器将不会定义它。类和命名空间版本之间的一个区别是“ i”的地址(如果在两个或更多翻译单元中使用)对于类成员将是相同的。在使用地址的地方,您必须对其进行定义:

// a.h
class A {
public:
  static const int i = 0;
};

// a.cc
#include "a.h"
const int A::i;            // Definition so that we can take the address

回答by Ferruccio

It's a small space optimization.

这是一个小空间优化。

When you say

当你说

const int foo = 42;

You're not defining a constant, but creating a read-only variable. The compiler is smart enough to use 42 whenever it sees foo, but it will also allocate space in the initialized data area for it. This is done because, as defined, foo has external linkage. Another compilation unit can say:

您不是在定义常量,而是在创建只读变量。编译器足够聪明,可以在看到 foo 时使用 42,但它也会在已初始化的数据区中为它分配空间。这样做是因为,正如定义的那样, foo 具有外部链接。另一个编译单元可以说:

extern const int foo;

extern const int foo;

To get access to its value. That's not a good practice since that compilation unit has no idea what the value of foo is. It just knows it's a const int and has to reload the value from memory whenever it is used.

获得它的价值。这不是一个好的做法,因为该编译单元不知道 foo 的值是什么。它只知道它是一个 const int 并且在使用时必须从内存中重新加载该值。

Now, by declaring that it is static:

现在,通过声明它是静态的:

static const int foo = 42;

The compiler can do its usual optimization, but it can also say "hey, nobody outside this compilation unit can see foo and I know it's always 42 so there is no need to allocate any space for it."

编译器可以执行其通常的优化,但它也可以说“嘿,此编译单元之外的任何人都无法看到 foo,我知道它始终为 42,因此无需为其分配任何空间。”

I should also note that in C++, the preferred way to prevent names from escaping the current compilation unit is to use an anonymous namespace:

我还应该注意,在 C++ 中,防止名称转义当前编译单元的首选方法是使用匿名命名空间:

namespace {
    const int foo = 42; // same as static definition above
}

回答by Kevin

It's missing an 'int'. It should be:

它缺少一个“int”。它应该是:

const static int foo = 42;

In C and C++, it declares an integer constant with local file scope of value 42.

在 C 和 C++ 中,它声明了一个整数常量,其本地文件范围的值为 42。

Why 42? If you don't already know (and it's hard to believe you don't), it's a refernce to the Answer to Life, the Universe, and Everything.

为什么是 42?如果你还不知道(而且很难相信你不知道),它是对生命、宇宙和一切答案的参考

回答by Black

To all the great answers, I want to add a small detail:

对于所有出色的答案,我想添加一个小细节:

If You write plugins (e.g. DLLs or .so libraries to be loaded by a CAD system), then staticis a life saver that avoids name collisions like this one:

如果您编写插件(例如要由 CAD 系统加载的 DLL 或 .so 库),那么static是一种避免名称冲突的救命稻草,如下所示:

  1. The CAD system loads a plugin A, which has a "const int foo = 42;" in it.
  2. The system loads a plugin B, which has "const int foo = 23;" in it.
  3. As a result, plugin B will use the value 42 for foo, because the plugin loader will realize, that there is already a "foo" with external linkage.
  1. CAD系统加载了一个插件A,它有一个“const int foo = 42;” 在里面。
  2. 系统加载了一个插件B,它有“const int foo = 23;” 在里面。
  3. 结果,插件 B 将为 foo 使用值 42,因为插件加载器将意识到,已经有一个带有外部链接的“foo”。

Even worse: Step 3 may behave differently depending on compiler optimization, plugin load mechanism, etc.

更糟糕的是:根据编译器优化、插件加载机制等,第 3 步的行为可能会有所不同。

I had this issue once with two helper functions (same name, different behaviour) in two plugins. Declaring them static solved the problem.

我曾经在两个插件中使用两个辅助函数(相同的名称,不同的行为)遇到过这个问题。将它们声明为静态解决了问题。

回答by Alexey Pelekh

According to C99/GNU99 specification:

根据 C99/GNU99 规范:

  • static

    • is storage-class specifier

    • objects of file level scope by default has externallinkage

    • objects of file level scope with static specifier has internallinkage
  • const

    • is type-qualifier (is a part of type)

    • keyword applied to immediate left instance - i.e.

      • MyObj const * myVar;- unqualified pointer to const qualified object type

      • MyObj * const myVar;- const qualified pointer to unqualified object type

    • Leftmost usage - applied to the object type, not variable

      • const MyObj * myVar;- unqualified pointer to const qualified object type
  • static

    • 是存储类说明符

    • 默认情况下文件级范围的对象具有外部链接

    • 具有静态说明符的文件级范围的对象具有内部链接
  • const

    • 是类型限定符(是类型的一部分)

    • 应用于直接左实例的关键字 - 即

      • MyObj const * myVar;- 指向 const 限定对象类型的非限定指针

      • MyObj * const myVar;- 指向非限定对象类型的 const 限定指针

    • 最左边的用法 - 应用于对象类型,而不是变量

      • const MyObj * myVar;- 指向 const 限定对象类型的非限定指针

THUS:

因此:

static NSString * const myVar;- constant pointer to immutable string with internal linkage.

static NSString * const myVar;- 指向具有内部链接的不可变字符串的常量指针。

Absence of the statickeyword will make variable name global and might lead to name conflicts within the application.

缺少static关键字将使变量名称成为全局变量,并可能导致应用程序中的名称冲突。

回答by paxos1977

In C++,

在 C++ 中,

static const int foo = 42;

is the preferred way to define & use constants. I.e. use this rather than

是定义和使用常量的首选方式。即使用这个而不是

#define foo 42

because it doesn't subvert the type-safety system.

因为它不会破坏类型安全系统。

回答by Jim Buck

Yes, it hides a variable in a module from other modules. In C++, I use it when I don't want/need to change a .h file that will trigger an unnecessary rebuild of other files. Also, I put the static first:

是的,它对其他模块隐藏了一个模块中的变量。在 C++ 中,当我不想/不需要更改会触发其他文件不必要的重建的 .h 文件时,我会使用它。另外,我把静态放在第一位:

static const int foo = 42;

Also, depending on its use, the compiler won't even allocate storage for it and simply "inline" the value where it's used. Without the static, the compiler can't assume it's not being used elsewhere and can't inline.

此外,根据它的用途,编译器甚至不会为它分配存储空间,而是简单地“内联”使用它的值。如果没有静态,编译器就不能假设它没有在其他地方使用,也不能内联。

回答by Roskoto

This ia s global constant visible/accessible only in the compilation module (.cpp file). BTW using static for this purpose is deprecated. Better use an anonymous namespace and an enum:

此 ia 全局常量仅在编译模块(.cpp 文件)中可见/可访问。顺便说一句,不推荐为此目的使用静态。最好使用匿名命名空间和枚举:

namespace
{
  enum
  {
     foo = 42
  };
}