编译C结构

时间:2014-09-29 06:48:13

标签: c struct

这是我的代码:

#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!”。不明白这里发生了什么。

2 个答案:

答案 0 :(得分:4)

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

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

之间使用标量常量

但是,许多C89 / 90编译器忽略了该标准要求,并允许用户在为本地对象编写{}初始值设定项时指定非常量值。不幸的是,如果用户在struct初始值设定项中指定了复杂的{}对象,就会立即产生歧义,如

safe s = { numbers, "RAMCON" };

语言标准不允许这样做,因此不清楚这个numbers初始化程序应该适用于什么。有两种解释方法:

  1. 该语言的现有规则表示编译器必须自动进入struct嵌套的每个级别,并将{}中的顺序初始化器应用于以这种方式找到的所有顺序标量字段(实际上,它有点复杂,但这是一般的想法。

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

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

  3. 后一种行为是你在你的例子中所期望的(并且,如果我没有记错,这是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试图告诉你的相同问题。如果您声明goldnumbers静态,则可以使这些消失。