这是我的代码:
#include <stdio.h>
typedef struct {
const char *description;
float value;
int age;
} swag;
typedef struct {
swag *swag;
const char *sequence;
} combination;
typedef struct {
combination numbers;
const char *make;
} safe;
int main(void)
{
swag gold = { "GOLD!", 100000.0 };
combination numbers = { &gold, "6503" };
safe s = { numbers, "RAMCON" };
printf("Contents = %s\n", s.numbers.swag->description);
getchar();
return 0;
}
每当我使用VS开发人员控制台编译它时,我都会收到此错误:错误C2440:'initializing':无法从'combination'转换为'swag *'。 但是,如果我使用gcc,控制台只会打印:“GOLD!”。不明白这里发生了什么。
答案 0 :(得分:4)
您偶然发现的是各种C89 / 90编译器中使用的流行的非标准编译器扩展的特定于实现的变体。
经典C89 / 90的严格规则禁止在{}
初始值设定项中使用非常量对象。这立即意味着无法在初始化程序中的struct
之间指定整个{}
对象,因为这会违反上述要求。根据该规则,您只能在{}
。
但是,许多C89 / 90编译器忽略了该标准要求,并允许用户在为本地对象编写{}
初始值设定项时指定非常量值。不幸的是,如果用户在struct
初始值设定项中指定了复杂的{}
对象,就会立即产生歧义,如
safe s = { numbers, "RAMCON" };
语言标准不允许这样做,因此不清楚这个numbers
初始化程序应该适用于什么。有两种解释方法:
该语言的现有规则表示编译器必须自动进入struct
嵌套的每个级别,并将{}
中的顺序初始化器应用于以这种方式找到的所有顺序标量字段(实际上,它有点复杂,但这是一般的想法。
这正是您的编译器所做的。它使用了第一个初始化器numbers
,它找到了第一个标量字段s.numbers.swag
并尝试将前者应用于后者。这预计会产生您观察到的错误。
其他编译器对该扩展采用了更精细的方法。当编译器看到{}
列表中的下一个初始化程序与左侧的目标字段具有相同的类型时,它没有&#34;打开&#34;目标字段并没有进入下一级嵌套,而是使用整个初始值设定值来初始化整个目标字段。
后一种行为是你在你的例子中所期望的(并且,如果我没有记错,这是C99所要求的行为),但你的C89 / 90编译器的行为符合第一种方法。
换句话说,当您编写C89 / 90代码时,在本地{}
初始化程序中指定非常量对象时,通常可以使用该非标准扩展。但是最好避免在这样的初始值设定项中使用struct
对象,并且只使用标量初始值设定项。
答案 1 :(得分:0)
看起来像初始化程序的问题。如果你使用gcc的正确选项,它会告诉你:
$ gcc -Wall -ansi -pedantic x.c
x.c: In function ‘main’:
x.c:21: warning: initializer element is not computable at load time
x.c:22: warning: initializer element is not computable at load time
这可能是VS试图告诉你的相同问题。如果您声明gold
和numbers
静态,则可以使这些消失。