What Does 'Const Static' Mean in C and C++

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

It has uses in both C and C++.

As you guessed, the static part limits its scope to that compilation unit. It also provides for static initialization. const just 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.

All that is how C treats these variables (or how C++ treats namespace variables). In C++, a member marked static is 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 const on there will warn you if any code would try to modify that.

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

What is the difference between static const and const?

The difference is the linkage.

// At file scope
static const int a=5; // internal linkage
const int i=5; // external linkage

If the i object is not used outside the translation unit where it is defined, you should declare it with the static specifier.

This enables the compiler to (potentially) perform further optimizations and informs the reader that the object is not used outside its translation unit.

C++ semantics of `static const` vs `const`

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.

Static, define, and const in C


static double m = 30000; 

double foo(double x, double y) {
return x/m + y;
}

This doesn't win you anything. A copy of m has to be made to do the computation.
Also if you do:

double bar( double x, double y) {
m += x + y;
return m;
}

Then all calls to bar will change m.
Static variables outside of functions (or classes) are really global variables with file scope. Other files can't get at them by extern

Static variables inside a function are still like global variables, except that even other functions in the same file can't see them directly.

const double m = 30000;

This is better and in many cases best. If the compiler sees this global const and then sees a reference to m then it knows that rather than generate code to load the value from where ever it is (which likely requires loading a literal address into a register first) to a register or stack position to do computations it can just make a register be 30000 or sometimes generate an instruction with 30000 encoded right in there.

The down side to this is that the compiler has to assume that other souce files will want to read m and has to actually store a copy as a variable (but a constant variable) in the object file.

I'm not sure if it is standard but you can sometimes do extern const double m = 30000; and the compiler will use 30000 to optimize and assume that another file actually has a copy of m that will be stored in the executable. You can also do static const double m = 30000; and the compiler can assume that no one else will expect that a copy of m is stored in the object code generated from this source file.

Doing

#define m 30000

is more risky. You will not get a warning or error if previously there was another m declared as a variable, constant, or function. Also, for preprocessor macros like this it is easy to mess up.
For example:

#define BASE_ADDRESS 48
#define MY_OFFSET 9
#define MY_ADDRESS BASE_ADDRESS+MY_OFFSET
...
return MY_ADDRESS*4;

Yes, this is a stupid example, but what this looks like after the preprocessor gets done with it is

...
return 48+9*4;

Which is

 return 48+(9*4);

And that's not what you probably wanted.

Another place where macros are bad is when you have large constants, such as strings. Strings require that they be addressable by pointer and are more difficult to optimize away than integers and floating point literal or constant numbers. You could easily make a very large program if you had lots of stuff like:

#define JIM "Jim"
#define JOHN "John"

and then used JIM and JOHN all over your programs because the compiler might not be able to see that you really only needed the strings "Jom" and "John" once in the program.

That being said, it is not uncommon to see constants being declared like that, and often they are properly done that way by people who know what they are doing.

What is the difference between static const int and static int const?

The grammar for declaration specifiers is given in C 2018 6.7 1, and it shows that specifiers for storage class (such as static), type (such as short or double), qualifiers (such as const), functions (inline and _Noreturn), and alignment may appear in any order. Nothing in clause 6.7 gives any meaning to the order in which the specifiers appear, so we may presume any combination of specifiers has the same meaning regardless of order.

The only mention of “order” in this regard appears in 6.7.2 2, which says “… the type specifiers may occur in any order, possibly intermixed with the other declaration specifiers.” So you can write long static int const long for static const long long int, just as you can say “square red big house” instead of “big square red house”—there is no rule against it, but it will seem funny to people and may throw them off.

Note that the * that indicates a pointer, as well as ( and ) for either grouping or argument lists and [ and ] for subscripts are not declaration specifiers and may not be freely reordered with declaration specifiers. (They are in fact part of a declarator, which is a separate part of a declaration from the declaration-specifiers.)

However, the standard describes using storage-class specifiers after other specifiers or qualifiers as obsolescent, in 6.11.5:

The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.

“Obsolescent” means the feature may be considered for withdrawal in future revisions of the standard (per Introduction paragraph 2). Thus, compilers that issue a warning for using const static are suggesting a change that helps prepare the source code for a future version of C.

static const vs #define vs enum

It depends on what you need the value for. You (and everyone else so far) omitted the third alternative:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

Ignoring issues about the choice of name, then:

  • If you need to pass a pointer around, you must use (1).
  • Since (2) is apparently an option, you don't need to pass pointers around.
  • Both (1) and (3) have a symbol in the debugger's symbol table - that makes debugging easier. It is more likely that (2) will not have a symbol, leaving you wondering what it is.
  • (1) cannot be used as a dimension for arrays at global scope; both (2) and (3) can.
  • (1) cannot be used as a dimension for static arrays at function scope; both (2) and (3) can.
  • Under C99, all of these can be used for local arrays. Technically, using (1) would imply the use of a VLA (variable-length array), though the dimension referenced by 'var' would of course be fixed at size 5.
  • (1) cannot be used in places like switch statements; both (2) and (3) can.
  • (1) cannot be used to initialize static variables; both (2) and (3) can.
  • (2) can change code that you didn't want changed because it is used by the preprocessor; both (1) and (3) will not have unexpected side-effects like that.
  • You can detect whether (2) has been set in the preprocessor; neither (1) nor (3) allows that.

So, in most contexts, prefer the 'enum' over the alternatives. Otherwise, the first and last bullet points are likely to be the controlling factors — and you have to think harder if you need to satisfy both at once.

If you were asking about C++, then you'd use option (1) — the static const — every time.

Is C compiler obligated to place a static const in memory?

No, it isn't as long as you do not tell it to otherwise. It can very well use the constant as literal (immediate) values in assembler instructions.

Telling otherwise could be

  • declaring the const volatile (Telling the compiler: "We don't change it, but somebody else could")
  • declaring and/or using i.e. dereferencing a pointer to the constwhich is not explicitely const

What does static mean in C?


  1. A static variable inside a function keeps its value between invocations.
  2. A static global variable or a function is "seen" only in the file it's declared in

(1) is the more foreign topic if you're a newbie, so here's an example:

#include <stdio.h>

void foo()
{
int a = 10;
static int sa = 10;

a += 5;
sa += 5;

printf("a = %d, sa = %d\n", a, sa);
}


int main()
{
int i;

for (i = 0; i < 10; ++i)
foo();
}

This prints:

a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60

This is useful for cases where a function needs to keep some state between invocations, and you don't want to use global variables. Beware, however, this feature should be used very sparingly - it makes your code not thread-safe and harder to understand.

(2) Is used widely as an "access control" feature. If you have a .c file implementing some functionality, it usually exposes only a few "public" functions to users. The rest of its functions should be made static, so that the user won't be able to access them. This is encapsulation, a good practice.

Quoting Wikipedia:

In the C programming language, static
is used with global variables and
functions to set their scope to the
containing file. In local variables,
static is used to store the variable
in the statically allocated memory
instead of the automatically allocated
memory. While the language does not
dictate the implementation of either
type of memory, statically allocated
memory is typically reserved in data
segment of the program at compile
time, while the automatically
allocated memory is normally
implemented as a transient call stack.

And to answer your second question, it's not like in C#.

In C++, however, static is also used to define class attributes (shared between all objects of the same class) and methods. In C there are no classes, so this feature is irrelevant.

static const vs const static

The order of qualifiers and specifiers does not matter. Per C 2011 [N1570] 6.7.3 10:

… the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

and 6.7.2 2:

… the type specifiers may occur in any order, possibly intermixed with the other declaration specifiers.

However, the standard describes using storage-class specifiers after other specifiers or qualifiers as obsolescent, in 6.11.5:

The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.

“Obsolescent” means the feature may be considered for withdrawal in future revisions of the standard (per Introduction paragraph 2). Thus, compilers that issue a warning for using const static are suggesting a change that helps prepare the source code for a future version of C.



Related Topics



Leave a reply



Submit