问题
Can someone please explain why this code...
// main.c
#include <stddef.h>
static const int g_a = 1;
static const char* g_b = "hello";
static const char* g_c[] = { "a", "b", NULL };
typedef struct Foo
{
int a;
const char* b;
const char** c;
} Foo;
static Foo f[] =
{
{ g_a,
g_b,
g_c }
};
int main( int argc, char* argv[] )
{
return 0;
}
...produces this error:
> gcc --version && gcc -g main.c
gcc (GCC) 8.2.1 20181215 (Red Hat 8.2.1-6)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
main.c:19:5: error: initializer element is not constant
g_b,
^~~
main.c:19:5: note: (near initialization for 'f[0].b')
I understand that the compiler is asking for a constant to initialize f[0].b, so the following initialization is a solution to the compile error:
static Foo f[] = { { g_a, "hello", g_c } };
But why does the compiler not issue a similar "constant required" error for the initialization of f[0].c? (Or, for that matter, f[0].a?) Why is this only an issue for f[0].b?
回答1:
f[0].a has type "non-constant int" and is initialized by the value of g_a that is of type "const int" which cannot change at run time and is known at compile time. So no error here.
f[0].b has type "non-constant pointer to const char" and should be initialized by the value of g_b that is also a "non-constant pointer to const char". Even if it has an initializer g_b can change at run time, and IIRC the initialization sequence is not determined. So its value is not known at compile time, hence the error.
f[0].c has type "non-constant pointer to non-constant pointer(s) to const char" and is initialized by g_c that is an array of elements of type "non-constant pointer to const char". The symbol of an array can be used as a constant pointer which is known at compile time. So no error here.
This is what you are missing, I think: If you want a pointer to be const, place the modifier at the pointer, behind the *, not at the pointed value, like this: [const] char * const pointer.
回答2:
Formal definitions: look at the 'address constant' definition: "C Language refence manual 6.19":
The address constant is a pointer to an object that has static storage duration or a pointer to a function. You can get these by using the & operator or through the usual conversions of array and function names into pointers when they are used in expressions. The operators [], ., ->, & (address of) and * (pointer dereference) as well as casts of pointers can all be used in the expression as long as they don't involve accessing the value of any object.
Practical answer: "C" requires that static variable are initialized to constant expression which can be calculated at compile time. The constant calculation can use addresses of static/global variables - where the actual address is not known until link time.
In those cases (e.g., char *char_p = &char_var, or similar), the compiler will generate assembly instructions to mark the calculated value for 'relocation' at link time. The relocation as expressed by a static/global variable. At link time, the linker will add the actual address of the static/global to the stored value.
Consider: char char_var = 'A' ; char *char_p = &char_var;
.file "b.c"
.text
.globl char_var
.data
.type char_var, @object
.size char_var, 1
# Char var initialized with a constant (65=A)
char_var:
.byte 65
.globl char_p
.section .data.rel.local,"aw",@progbits
.align 8
.type char_p, @object
.size char_p, 8
# Initialize char_p to global symbol, actual address resolved at link time.
char_p:
.quad char_var
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
.section .note.GNU-stack,"",@progbits
There is limit to the to the linker ability to calculate address at link time. It is limited to static address +/- constant offsets:
- &static_var
- &static_var + compile time constant
- &static_var - compile time constant
But not '&static_var_1 - &static_var_2', which will give an error message hinting at the limit:
b.c:3:9: error: initializer element is not computable at load time
int v = &char_var - &char_v2 ;
来源:https://stackoverflow.com/questions/58466193/why-is-constant-initialization-need-for-static-char-but-not-static-char