结构标签可以在其范围之前使用吗?

时间:2017-08-17 00:15:58

标签: c struct

在以下示例中:

#include <stdio.h>
#include <stdlib.h>

struct B b;
struct B{int a;}; 

struct B;

int main()
{
    b.a=3;
    printf("%d\n", b.a);
    return 0;
}

结构标记B的文件范围从其第一个定义/声明struct B{int a;};开始。 struct B b;如何在B的范围之前引用B而没有错误?

struct B;是结构类型声明还是结构类型定义?为什么它不与同一文件范围中的其他定义struct B{int a;};冲突?

2 个答案:

答案 0 :(得分:4)

struct B;是一个结构声明。可以存在同一对象的任意数量的声明。对于具有多个可能声明的对象类型,声明必须兼容 - 例如,您可以为同一个函数使用多个原型,但是它们需要使用相同的参数和返回类型。对于一个结构,只有一种方法可以在不定义它的情况下声明它,它只是说“有一个名为B的结构”。所以可以根据需要重复struct B;次。

struct B{int a;};是结构定义。给定对象只能有一个定义。对象的某些使用需要先前的定义,其他只需要事先声明。例如,您可以定义一个变量,其类型是指向未定义结构的指针:

struct S;
struct S *p = NULL;

但是你不能定义一个类型是未定义结构的变量:

struct S;
struct S s = {0};

这种差异的原因是尚未定义的结构是不完整类型 - 编译器没有大小的类型。这不是定义指针​​的问题,但定义不完整类型的对象是一个问题:编译器不知道需要多少内存。

此时,您可能想知道为什么struct B b;没问题。毕竟,struct B甚至没有被宣布,更不用说定义了。

为什么它没问题的第一部分是struct B b;在传递中声明结构B。因此,当需要struct Bb做某事时,结构刚刚被声明。

为什么没关系的第二部分是struct B b;并不完全是一个定义。如果它是一个定义,那么编译器需要知道要保留多少空间,而不完整的类型则不行。如果变量是在函数中定义的,那么会发生这种情况:

void f(void) {
    struct B b; // error: storage size of ‘b’ isn’t known
}

但是当struct B b;位于文件的顶层时,它是暂定定义。暂定的定义是宣言;为此,不需要定义结构。当编译器到达文件末尾时,任何没有正确定义且需要定义的暂定定义都将成为定义。此时,需要定义结构。在您的示例程序中,b具有暂定定义,该定义在文件末尾成为正确的定义。

如果变量未被使用,则可以不定义结构,因为如果不使用变量,可以声明具有不完整类型的变量。

struct B b;
// end of file

但如果变量以需要完整类型的方式使用,则必须在该点定义结构。

struct B b;
void f(void) {
    sizeof(b); // error: invalid application of ‘sizeof’ to incomplete type ‘struct B’
}
struct B{int a;}; // too late

答案 1 :(得分:0)

问题:结构B b怎么样;在B的范围之前参考B而没有错误? 答案:来自第1471节http://c0x.coding-guidelines.com/6.7.2.3.html, “如果是 struct-or-union identifier 形式的类型说明符 除了作为上述形式之一的一部分之外,不会发生标识符作为标记的其他声明,然后它声明一个不完整的结构或联合类型,并将标识符声明为该类型的标记。“
因此,您可以在结构类型定义之前将struct标记用作前向声明。

问题:是结构B;结构类型声明或结构类型定义?为什么它不与其他定义struct B {int a;};冲突?在同一文件范围内? 答:来自第1472节中的相同链接, “如果形式为 struct-or-union identifier 枚举标识符的类型说明符不是作为上述表单之一的一部分而发生,并且标识符的声明为标签是可见的,然后它指定与其他声明相同的类型,并且不重新声明标签。“

struct B; 是结构类型声明, struct B {int a;}; 是结构类型定义,它们不会相互冲突。 您可以选择使用 typedef 来消除混淆并显示对结构声明的更多可见性:

typedef struct B B;
struct B{
    int a;
}; 
B b;