我可以在C中的结构中静态初始化char *吗?

时间:2011-04-30 10:11:30

标签: c static struct initialization

有没有办法在C中做这样的事情?

char* str[] = { "abc" };
struct test { char* str_in_struct; } tests[] = {
  { str[0] }
};

如果我尝试编译它,gcc说:

main.c:6: error: initializer element is not constant
main.c:6: error: (near initialization for ‘tests[0].str_in_struct’)
main.c:6: warning: missing initializer
main.c:6: warning: (near initialization for ‘tests[0].str_in_struct’)

1 个答案:

答案 0 :(得分:4)

有两种情况可以出现代码 - 在函数内部,在函数外部。

  • 代码在一个上下文中有效 - 在函数内部。
  • 代码在其他上下文中无效 - 在函数外部。

这可能解释了编译器是否接受代码的不同观点。

鉴于代码:

char* str[] = { "abc" };
struct test { char* str_in_struct; } tests[] = { { str[0] } };

void somefunc(void)
{ 
    char* str[] = { "abc" };
    struct test tests[] = { { str[0] } };
}

编译(在MacOS X 10.6.7上使用GCC 4.1.2)产生:

$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -c xx.c
xx.c:2: error: initializer element is not constant
xx.c:2: error: (near initialization for ‘tests[0].str_in_struct’)
xx.c:2: warning: missing initializer
xx.c:2: warning: (near initialization for ‘tests[0].str_in_struct’)
xx.c:5: warning: no previous prototype for ‘somefunc’
xx.c: In function ‘somefunc’:
xx.c:7: warning: unused variable ‘tests’
$

第5和第7行的警告非常准确;第2行的错误也是准确的。

有什么问题?

基本上,str[0]需要链接器无法执行(或不需要执行)的计算。

在此代码修订版中,test2没问题,但teststest3不是:

struct test { char* str_in_struct; };
char *str[] = { "abc" };
char  pqr[]  =   "abc";
char *xyz    =   "abc";
struct test tests[] = { { str[0] } };
struct test test2[] = { { pqr } };
struct test test3[] = { { xyz } };

void somefunc(void)
{
    char* str[] = { "abc" };
    struct test tests[] = { { str[0] } };
}

您可以在外部初始值设定项中引用数组名称。你不能引用数组元素,也不能引用指针变量的值。


解释评论/问题:

  

[它]似乎如果char str4[][4] = { "abc", "d" };,则struct test { char* str_in_struct; } test4[] = { { str4[1] } };有效。那么,你可以引用数组元素,但只有它们的大小已知?

我还没有完全正确地描述它 - 你是对的。我给出了部分答案,但没有给出完整答案。基本上,'out of function'初始值设定项中的表达式必须是常量。它不像'只有尺寸已知'那么简单。问题在于是否可以在不从内存中读取值的情况下计算初始值设定项中的表达式。

使用str[0](原始版本),您必须阅读存储在str[0]的值;与xyz类似。使用pqr版本和str4版本(请注意与评论相比的额外4),值(地址)pqrstr4[1]可通过以下方式计算:链接器没有读取存储在那里的值。

在C99标准中,§6.7.8初始化说:

  

¶4具有静态存储持续时间的对象的初始值设定项中的所有表达式都应为   常量表达式或字符串文字。

§6.6常表达式说:

  

¶2可以在翻译期间而不是运行时评估常量表达式   因此可以在常数可能的任何地方使用。

  

¶7初始值设定项中的常量表达式允许更大的纬度。这样的常数   表达式应为或评估为以下之一:

     

- 算术常量表达式,
   - 空指针常量,
   - 地址常量或
   - 对象类型的地址常量加上或减去整数常量表达式。

     

¶8算术常量表达式应具有算术类型且只能具有   操作数是整数常量,浮点常量,枚举常量,字符   常量和sizeof表达式。在算术常量表达式中转换运算符   只能将算术类型转换为算术类型,除非作为操作数的一部分   结果为整数常量的sizeof运算符。

     

¶9地址常量是一个空指针,指向一个指定静态对象的左值的指针   存储持续时间,或指向功能指示符的指针;它应该使用明确创建   一元&运算符或整数常量强制转换为指针类型,或隐式使用   数组或函数类型的表达式。数组下标[]和成员访问.   和->运算符,地址&和间接*一元运算符和指针强制转换   用于创建地址常量,但对象的值不应该是   通过使用这些运算符访问。

请注意限定符',但不能使用这些运算符访问对象的值。这与我之前在答案的扩展中所写的内容一致。特别是,str4[1]的值只需要数组str4的地址常量加上一个整数常量表达式(项目符号列表中的最后一个选项)。同样,pqr是地址常量(项目符号列表中的第三个替代)。但是str[0]xyz初始值设定项必须访问对象的值,这是不允许的。