2

Is it valid to declare in my headers a const variable, but define it as a non-const variable for internal use?

3 Answers3

5

The only logical way of declaring variables in the header file is to declare them as extern

As #include only inserts the text of the header file into the source code file (https://godbolt.org/z/nor8nz) you can simply test you idea in the single source file:

extern const int x;

int x;

https://godbolt.org/z/PWEzGM

You will get the error:

1
ARM gcc 8.2
- 347ms

<source>:4:5: error: conflicting type qualifiers for 'x'
 int x;
     ^
<source>:2:18: note: previous declaration of 'x' was here
 extern const int x;
                  ^
Compiler returned: 1
0___________
  • 60,014
  • 4
  • 34
  • 74
3

No, this causes undefined behavior.

C17 6.6.7 (2):

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

6.7.3 (11):

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

Since const is a qualifier, types such as int and const int are not compatible, and therefore it is undefined behavior to have both an int and a const int declaration of the same object. (And the definition of the object is itself a declaration, so it counts.)

One of many possible undesired consequences, in practice, could be that in source files (translation units) that have a const declaration, the compiler may assume that the variable is actually constant, and may fail to notice if it is modified. For example, code like the following:

#include <stdio.h>
extern const int x;
void bar(void);
void foo(void) {
    printf("%d\n", x);
    bar();
    printf("%d\n", x);
}

may cache the value of x in a callee-saved register across the call to bar(), and so will always print the same value twice. See on godbolt. This would happen even if another file contains

int x = 5;
void bar(void) {
    x = 6;
}
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
1

I hope for better answers that can address the direct question about the validity.

But this is almost certainly a bad approach. My suggestion is to use a function that returns the value instead. Another option would be to use a pointer to const. Something like:

int x;
int *const ptr = &x;

Using globals the way you describe is dangerous territory. If I ever would like to do something like that, I'd probably just accept that I have to be really careful.

One might be tempted to use a pointer like this:

const int x;
int *ptr = &x; // Bad, bad idea

But do NOT try to do that, as it invokes undefined behavior. Source: Can we change the value of an object defined with const through pointers?

klutt
  • 30,332
  • 17
  • 55
  • 95