2014-09-29 88 views
3

这是我的代码:编译C结构

#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:“初始化”:无法从“组合”转换为“赃物* ”。 但是,如果我使用gcc控制台只是打印:“黄金!”。不明白这里发生了什么。

+0

@remyabel我正在使用Visual Studio 13开发人员命令提示符。 – 2014-09-29 06:53:48

+0

对不起,我发布了错误编译器的链接。 – 2014-09-29 06:54:38

+0

@remyabel任何线索为什么我得到这个错误? – 2014-09-29 06:56:13

回答

4

你偶然发现的是在各种C89/90编译器中使用的流行的非标准编译器扩展的实现特定变体。

经典C89/90的严格规则禁止在{}初始值设定项中使用非常量对象。这立即意味着在初始化器中指定{}之间的整个对象是不可能的,因为这会违反上述要求。根据该规则,您只能使用{}之间的标量常量。

但是,许多C89/90编译器忽略该标准要求,并允许用户在为局部对象编写{}初始值设定项时指定非常量值。不幸的是,如果用户指定的复杂struct对象{}初始化内,如本立即创建了一个模棱两可的

safe s = { numbers, "RAMCON" }; 

的语言标准并没有允许这样做,因为这个原因,目前还不清楚这numbers初始化应适用什么至。有两种方法来解释这一点:

  1. 语言的现有规则说,编译器必须自动进入struct嵌套的每个级别,并从{}申请顺序初始化,以这种方式找到的所有连续的标量场(实际上,这有点复杂,但这是一般的想法)。

    这正是你的编译器所做的。它花了第一个初始化程序numbers,发现第一个标量字段s.numbers.swag并试图将前者应用于后者。这预计会产生你观察到的错误。

  2. 其他编译器对该扩展采取了更详细的方法。当编译器看到{}列表中的下一个初始化程序与左侧的目标字段的类型相同时,它没有“打开”目标字段,也没有进入下一级嵌套,而是使用整个初始化器的值来初始化整个目标字段。

后者的行为是你在你的例子所期待的(如果我没有记错,这是C99所要求的行为),但你的C89/90的编译器按照第一种方法表现。

换句话说,当您编写C89/90代码时,当您在本地{}初始值设定项中指定非常量对象时,通常可以使用该非标准扩展。但是避免在这样的初始值设定项中使用struct对象并且仅使用标量初始值设定项是个好主意。

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 

这是propably了同样的问题VS是想告诉你。如果声明goldnumbers为静态,则可以使这些消失。

+0

我为什么要将它们初始化为静态? – 2014-09-29 07:07:03

+0

@AnasAyubi使元素在加载时可计算。 – Jens 2014-09-29 08:55:13