为什么GCC编译这个错误的代码?

时间:2012-12-08 18:01:51

标签: c

我尝试编译类似的东西:

struct A
{   int a;
    struct B
    {    int c;
    };
};

现在当我编译这段代码时,编译器会给我一条警告信息:

declaration does not declare anything [enabled by default]

我知道我没有定义struct B的任何实例。这意味着我将无法访问变量c。仍然编译器使用警告编译此代码。什么是重点?为什么编译器不会给出编译错误?

添加信息
struct A的大小等于我机器上int的大小!!

4 个答案:

答案 0 :(得分:4)

因为你可以这样做:

struct A
{   int a;
    struct B
    {    int c;
    };
};

int main()
{
    struct A a = {1};
    struct B b = {2};

    return a.a + b.c;
}

注意:

  • 在声明B后,您需要一个分号,而您的代码缺失
  • 这不是特别有用的,但我认为它可能起到一些纪录目的(即建议关系或类型之间的分组)
  • 在C ++中,第二个变量的类型为A::B,但C没有相同的作用域规则(所有结构只属于全局struct命名空间,实际上)

关于允许它的动机......

struct Outer {
    struct {
        int b;
    } anon;
    /* this ^ anonymous struct can only be declared inside Outer,
       because there's no type name to declare anon with */

    struct Inner {
        int c;
    } named;
    /* this ^ struct could be declared outside, but why force it to be
       different than the anonymous one? */

    struct Related {
        double d;
    };
    /* oh no we have no member declared immediately ... should we force this
       declaration to be outside Outer now? */

    struct Inner * (*function_pointer)(struct Related *);
    /* no member but we are using it, now can it come back inside? */

    struct Related excuse;
    /* how about now? */
};

一旦你允许这样的嵌套类型声明,我怀疑是否有任何特殊动机要求立即成为该类型的成员。

答案 1 :(得分:3)

这是合法的(但风格非常糟糕):

struct A {   
    int a;
    struct B {    
        int c;
    };
};
struct B B_instance;
struct A A_instance;

编译器不知道后来使用struct类型的变量,所以它确实不应该出错。

答案 2 :(得分:3)

通常,警告意味着代码可能不会按照您的意图执行,但在语言中是合法的。编译器说,“这可能不是你真正想做的,但我必须允许你这样做,因为语言说它是允许的。”编译器不能给你一个错误代码,因为C标准允许它,所以必须允许它(除非你特别要求这些事情的错误,例如使用GCC的-Werror选项将警告变成错误)。

C标准不会尝试定义程序中有意义的所有内容。例如,这些东西在C中是合法的:

3;
if (x) then foo(); else foo();
x = 4*0;

第一个语句没有副作用,并且不使用其返回值。但它在C中是合法的,因为声明可能只是一种表达。第二个语句只调用foo(),因此if毫无意义。在第三个陈述中,乘以四是没有意义的。

编写一个禁止所有没有意义的事情的C标准是非常困难的。这当然不值得努力。所以这是你答案的一部分:当编写C标准的委员会构建语言时,他们是否希望花费大量时间重写技术规范以排除那些没有意义的事情?有时是的,如果避免可能导致严重错误的东西似乎很有价值。但在大多数情况下,这不值得花时间,并且会不必要地使规范复杂化。

但是,编译器可以识别其中的一些并警告您。这有助于捕获许多印刷错误或其他错误。

另一方面,有时这些结构是由不寻常的情况引起的。例如,程序可能具有预处理程序语句,在构建不同目标或不同功能时以不同方式定义struct A。在其中一些目标中,可能struct B中不需要struct A成员,因此未声明它,而是声明struct B(类型,而不是对象)仍然存在只是因为以这种方式编写预处理程序语句更容易。

因此编译器需要允许这些内容,以避免干扰程序员编写各种程序。

答案 3 :(得分:1)

事实上,你在这里声明struct B,但你没有声明这种类型的变量。

这是一个警告,但你应该修复一个。也许你的意思是:

struct A
{   int a;
    struct B
    {
        int c;
    } c;
};