Why is constant initialization need for static char* but not static char**

情到浓时终转凉″ 提交于 2020-02-06 03:39:16

问题


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:

  1. &static_var
  2. &static_var + compile time constant
  3. &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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!