Is it permissible to consider extern global as const when the definition is not const?

Say I have a compilation block file1.c that declares a file scope variable like this:

int my_variable = 12; 

Then, in another file2.c compiler , I create an extern declaration for this variable, but declare it as const :

 extern const int my_variable; 

This compiles and works fine with gcc using -Wall -Wextra -ansi -pedantic . However, the C89 standard says that for two qualified types that must be compatible, both must have the same version of the compatible type. Adding const to the declaration adds a constraint rather than excluding it. Is this safe and valid C? What would be the best practice in setting this up with header files?

+5
source share
2 answers

This is clearly undefined because the ads do not match. As you noted, const int and int are not compatible types. Diagnostics is only required if they are displayed in one area.

In practice, this is unsafe, consider

 $ cat test1.c #include <stdio.h> extern const int n; void foo(void); int main(void) { printf("%d\n", n); foo(); printf("%d\n", n); } $ cat test2.c int n; void foo(void) { ++n; } $ gcc -std=c99 -pedantic test1.c test2.c && ./a.out 0 1 $ gcc -O1 -std=c99 -pedantic test1.c test2.c && ./a.out 0 0 

Gcc assumes that n does not change with foo() during optimization, since it can assume that the definition of n is of a compatible type, thus const .

You will most likely get the expected behavior with volatile -qualifying n in test1.c , but as for the C standard, it is still undefined.

The best way I can prevent the user n from being accidentally modified is to point to a pointer to const , something like

 int my_real_variable; const int *const my_variable = &my_real_variable; 

or maybe a macro

 #define my_variable (*(const int *)&my_variable) 

With C99, my_real_variable can be avoided through a compound literal:

 const int *const my_variable_ptr = &(int){ 12 }; 

It would be legal to discard const here (since the int object itself is not const ), but the cast was necessary, preventing accidental modification.

+5
source

In this case, the definition and declaration are displayed in separate translation units, so the compiler cannot perform type or qualifier checks. Symbols are resolved by the linker, in which case it seems that the linker does not apply the matching of this classifier.

If the definition and declaration appeared in the same translation unit; for example, if you put the extern declaration in the header file and include it in file1.c, then I would suggest that the compiler would complain. Having placed them in separate translation units, the compiler never sees both, therefore, it cannot perform a check.

+4
source

Source: https://habr.com/ru/post/1210048/