为什么常量初始化需要 static char* 而不是 static char**
Why is constant initialization need for static char* but not static char**
有人可以解释为什么这段代码...
// 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;
}
...产生此错误:
> 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')
我了解到编译器要求一个常量来初始化f[0].b
,所以下面的初始化是编译错误的解决方案:
static Foo f[] = { { g_a, "hello", g_c } };
但是 为什么编译器不为 f[0].c
的初始化发出类似的 "constant required" 错误?(或者,就此而言,f[0].a
?) 为什么这只是 f[0].b
的问题?
f[0].a
具有类型 "non-constant int
" 并由类型为 "const int
" 的 g_a
的值初始化,该类型在 运行 时不能更改并且是在编译时已知。所以这里没有错误。
f[0].b
的类型为 "non-constant pointer to const char
",应由 g_b
的值初始化,该值也是 "non-constant pointer to const char
"。即使它有一个初始化程序 g_b
可以在 运行 时间更改,并且 IIRC 初始化顺序未确定。所以它的值在编译时是未知的,因此是错误的。
f[0].c
具有类型 "non-constant pointer to non-constant pointer(s) to const char
" 并由 g_c
初始化,它是类型 "non-constant pointer to const char
" 的元素数组。数组的符号可以用作编译时已知的常量指针。所以这里没有错误。
这就是你所缺少的,我认为: 如果你想要一个指针是 const
,请将修饰符放在指针上,在 [=24 后面=],而不是指向的值,像这样:[const] char * const pointer
.
正式定义:看'address constant'定义:"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.
实际答案:"C"要求将静态变量初始化为可在编译时计算的常量表达式。常量计算可以使用 static/global 变量的地址 - 实际地址直到 link 时间才知道。
在那些情况下(例如,char *char_p = &char_var,或类似的),编译器将生成汇编指令以在 [= 处标记 'relocation' 的计算值48=] 时间。由 static/global 变量表示的重定位。在 link 时,linker 将 static/global 的实际地址添加到存储值中。
考虑: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
linker 在 link 时计算地址的能力有限。它仅限于静态地址 +/- 常量偏移量:
- &static_var
- &static_var + 编译时间常数
- &static_var - 编译时间常量
但不是'&static_var_1 - &static_var_2',它会给出一条错误消息,提示已达到限制:
b.c:3:9: error: initializer element is not computable at load time
int v = &char_var - &char_v2 ;
有人可以解释为什么这段代码...
// 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;
}
...产生此错误:
> 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')
我了解到编译器要求一个常量来初始化f[0].b
,所以下面的初始化是编译错误的解决方案:
static Foo f[] = { { g_a, "hello", g_c } };
但是 为什么编译器不为 f[0].c
的初始化发出类似的 "constant required" 错误?(或者,就此而言,f[0].a
?) 为什么这只是 f[0].b
的问题?
f[0].a
具有类型 "non-constant int
" 并由类型为 "const int
" 的 g_a
的值初始化,该类型在 运行 时不能更改并且是在编译时已知。所以这里没有错误。
f[0].b
的类型为 "non-constant pointer to const char
",应由 g_b
的值初始化,该值也是 "non-constant pointer to const char
"。即使它有一个初始化程序 g_b
可以在 运行 时间更改,并且 IIRC 初始化顺序未确定。所以它的值在编译时是未知的,因此是错误的。
f[0].c
具有类型 "non-constant pointer to non-constant pointer(s) to const char
" 并由 g_c
初始化,它是类型 "non-constant pointer to const char
" 的元素数组。数组的符号可以用作编译时已知的常量指针。所以这里没有错误。
这就是你所缺少的,我认为: 如果你想要一个指针是 const
,请将修饰符放在指针上,在 [=24 后面=],而不是指向的值,像这样:[const] char * const pointer
.
正式定义:看'address constant'定义:"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.
实际答案:"C"要求将静态变量初始化为可在编译时计算的常量表达式。常量计算可以使用 static/global 变量的地址 - 实际地址直到 link 时间才知道。
在那些情况下(例如,char *char_p = &char_var,或类似的),编译器将生成汇编指令以在 [= 处标记 'relocation' 的计算值48=] 时间。由 static/global 变量表示的重定位。在 link 时,linker 将 static/global 的实际地址添加到存储值中。
考虑: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
linker 在 link 时计算地址的能力有限。它仅限于静态地址 +/- 常量偏移量:
- &static_var
- &static_var + 编译时间常数
- &static_var - 编译时间常量
但不是'&static_var_1 - &static_var_2',它会给出一条错误消息,提示已达到限制:
b.c:3:9: error: initializer element is not computable at load time
int v = &char_var - &char_v2 ;