174

In C++ specifically, what are the semantic differences between for example:

static const int x = 0 ;

and

const int x = 0 ;

for both static as a linkage and a storage class specifier (i.e. inside and outside a function).

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 11
    `static` is probably the most-overloaded keyword in C++. Your code's meaning varies widely depending on whether it is at namespace scope, at class scope, or at function scope. You might want to clarify that. – sbi Sep 14 '10 at 13:25
  • 3
    @sbi: I thought I did already. Function scope (where it is a storage class specifier) and file scope (where it is a linkage specifier). Class members and namespace scoped variables specifically are not of concern to me in respect to this question, although if anyone feels there is an interesting distinction, feel free to cover that too. – Clifford Sep 14 '10 at 16:09
  • @Clifford: I'm sorry I overlooked those last words. However, this revealed a misunderstanding on your part: In C++, file scope _is_ namespace scope. If you declare anything out side of any namespace, it will simply belong to the _global namespace_ (and is accessible through a prefixed `::` with no identifier in front). I'm not aware of any meaningful differences between the global namespace and any namespace nested in it. There certainly isn't any regarding `static` objects. – sbi Sep 14 '10 at 18:04
  • @sbi: I don't think I misunderstand anything; I use the term *file scope* when it has *static linkage*, and global scope when it has *external linkage*; I think that is a reasonable distinction since they have different visibility. In either case they would be in the global namespace, and namespaces can span multiple files. – Clifford Sep 14 '10 at 22:36
  • 1
    *linkage* is different from *visibility*, by using them interchangeably you're going to confuse the people you talk to and probably also yourself. – Ben Voigt Sep 15 '10 at 00:48
  • @Clifford: As Ben said. You are using the terms different than everybody else. – sbi Sep 15 '10 at 04:53
  • 1
    @Ben, @sbi: I did not intend to suggest that *file scope* and *static linkage* were the same, merely that static linkage *implies* file scope. In this sense *scope* (or visibility) is an attribute of static and external linkage, not a synonym for either. I feel that the original question remains clear and well formed, and that we are merely discussing the comments made in response to sbi's somewhat condescending remark. We are discussing imprecise semantics of English here rather than my understanding, so I think we can stop. – Clifford Sep 15 '10 at 11:10

2 Answers2

145

At file scope, no difference in C++. const makes internal linkage the default, and all global variables have static lifetime. But the first variant has the same behavior in C, so that may be a good reason to use it.

Within a function, the second version can be computed from parameters. In C or C++ it doesn't have to be a compile-time constant like some other languages require.

Within a class, basically the same thing as for functions. An instance const value can be computed in the ctor-initializer-list. A static const is set during startup initialization and remains unchanged for the rest of the program. (Note: the code for static members looks a little different because declaration and initialization are separated.)

Remember, in C++, const means read-only, not constant. If you have a pointer-to-const then other parts of the program may change the value while you're not looking. If the variable was defined with const, then no one can change it after initialization but initialization can still be arbitrarily complex.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    Is there anything called file scope? I was just checking $3.3 and I think the closest is 'namespace scope'. Is my understanding right? The C++03 standard mentions file scope only in the Appendices – Chubsdad Sep 15 '10 at 00:31
  • Didn't use the term "namespace scope" because that kinda goes off on a tangent of how members of most namespaces have external linkage by default but members of the anonymous namespace have internal linkage. Which has nothing to do with a question about `static` except that it makes static for linkage control obsolete. – Ben Voigt Sep 15 '10 at 00:46
  • 2
    I would suggest that *file scope* is an artefact of the linker rather than the compiler, so may not get much attention in the language standard. Strictly it is probably "compilation unit scope". – Clifford Sep 15 '10 at 11:28
  • 18
    +1 for the phrase "const means read-only, not constant", i.e., "Compiler, if you see someone trying to modify this const thing, bark very loudly." This is the reason something can be const & volatile at the same time. – Dan Sep 16 '10 at 16:07
  • 6
    It's more "Compiler, if you see me try to modify this const thing (or give someone else permission to do so)", bark very loudly. In most context, `const` applies to a view of the variable and not the variable itself, someone else can have a non-`const` view of the same variable, and the compiler will be quite silent when they modify it. – Ben Voigt Sep 16 '10 at 16:26
  • Not that this really means much of anything or changes the answer, but there's at least one situation in C++ where `const` really can mean constant: "If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions" – Michael Burr Jan 07 '11 at 17:43
  • @Michael: And thankfully, C++0x removes that special case behavior of `const` and introduces a separate keyword (`constexpr`) to deal with it in a much more general fashion. – Ben Voigt Jan 07 '11 at 17:46
  • 1
    @Ben: Just to be clear, C++0x doesn't remove that particular use of `const`, but the new `constexpr` can be used instead (and in other scenarios as well). Actually, the C++0x standard expands the ability to use `const` in that scenario to non-integral "literal types" as well. I think I'd prefer using `constexpr` for those cases, since you'd be breaking backward compatibility with pre-C++0x compilers anyway. – Michael Burr Jan 07 '11 at 18:26
  • 1
    @MichaelBurr: Yes absolutely. What I meant to say was that C++11 removed *the need* to use the special-cased behavior, as it's now possible to use `constexpr` consistently through the code. – Ben Voigt Mar 17 '14 at 22:09
  • @BenVoigt, can you elaborate more on "If you have a pointer-to-const then other parts of the program may change the value while you're not looking. ", it will be great if you can give an example. – Allanqunzi May 07 '15 at 05:29
  • 1
    @Allanqunzi: That sentence is pretty self-explanatory. All I can add is that the address of a non-`const` object implicitly converts to `const T*`, and storing that address in such a pointer-to-const doesn't make the original object `const`. Access through the pointer-to-const will generate a compiler error if it attempts to modify the object, but writing directly using the object's name, or through other pointers, will succeed. – Ben Voigt May 07 '15 at 14:51
  • I'm sorry but what does "const makes internal linkage the default," mean? Internal linkage? Does it mean linking from the the same file? – Chan Kim Nov 10 '20 at 13:42
  • @ChanKim: Your comment question is part of the FAQ, please read https://stackoverflow.com/q/1358400/103167 – Ben Voigt Sep 08 '22 at 16:00
10

C++17 standard draft on const implies static at file scope

This is the quote for what was mentioned at: https://stackoverflow.com/a/3709257/895245

C++17 n4659 standard draft 6.5 "Program and linkage":

3 A name having namespace scope (6.3.6) has internal linkage if it is the name of

  • (3.1) — a variable, function or function template that is explicitly declared static; or,
  • (3.2) — a non-inline variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or
  • (3.3) — a data member of an anonymous union.

Annex C (informative) Compatibility, C.1.2 Clause 6: "basic concepts" gives the rationale why this was changed from C:

6.5 [also 10.1.7]

Change: A name of file scope that is explicitly declared const, and not explicitly declared extern, has internal linkage, while in C it would have external linkage.

Rationale: Because const objects may be used as values during translation in C++, this feature urges programmers to provide an explicit initializer for each const object. This feature allows the user to put const objects in source files that are included in more than one translation unit.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: Seldom.

See also: Why does const imply internal linkage in C++, when it doesn't in C?

What you likely want to do instead on headers

Explained in detail at: What does 'const static' mean in C and C++?

  • pre C++17: extern in header, definition in cpp file
  • post C++17: inline variable on header
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • Thanks, though I don't think this is a chance in C++17 compared even with C++98, and the question was asked in 2010. Moreover, your answer deals only with static as a linkage specifier (at namespace scope), and the question asked specifically about the semantics in different contexts. – Clifford Jan 26 '19 at 10:49
  • @Clifford yes, definitely older than C++17, just lazy to read all standards ;-) Will clarify file scope part. – Ciro Santilli OurBigBook.com Jan 26 '19 at 10:51