是否可以在C中始终引用前向声明和非前向声明的结构?

时间:2017-01-08 10:49:28

标签: c struct typedef forward-declaration function-prototypes

这不适用于foo

struct Foo;

typedef struct
{
    int x;
}
Bar;

void foo (Foo *); // unknown type name ‘Foo’

void bar (Bar *);

typedef struct
{
    int y;
}
Foo;

这不适用于bar

struct Foo;

typedef struct
{
    int x;
}
Bar;

void foo (struct Foo *);

void bar (struct Bar *); ‘struct Bar’ declared inside parameter list

typedef struct
{
    int y;
}
Foo;

我的一些结构必须是前向声明的,因为它们作为指针传递,其中一些必须不是前向声明的,因为它们是作为值传递的。

有没有办法在C中声明类型,这样所有函数原型都可以始终以相同的方式始终引用自定义类型,无论它们是否是前向声明的?

5 个答案:

答案 0 :(得分:1)

struct Foo;

声明名为Foo的结构。但是,您必须声明名为Foo的结构的typedef Foo

#include  <stdio.h>

typedef struct Foo Foo;

typedef struct {
    int x;
} Bar;

void foo(Foo *);

void bar(Bar *);

struct Foo {
    int y;
};

int main(void) {
    printf("Hello, world!\n");
}

答案 1 :(得分:1)

第一项业务是指出在您的示例中没有struct Foo。只有一个没有标记的结构,typedefFoo 1

  

有没有办法在C中声明类型,这样所有函数原型都可以始终以相同的方式始终引用自定义类型,无论它们是否是前向声明的?

struct的定义或声明应该出现在函数参数列表中使用结构之前。否则,声明范围只是函数原型,几乎可以肯定不是你想要的。

实现目标的方法只有通过严格的编码才能实现。

前向声明是您真正需要的功能原型。在定义或调用函数本身之前,您不需要完整的结构定义。

struct Foo;
void foo (struct Foo); // Okay, only at the call site or definition site
                       // do we need the full struct definition.

简短example来演示

#include <stdio.h>

struct Foo;
void foo (struct Foo);

struct Foo
{
    int y;
};

int main(void) {

    struct Foo f = { .y = 1 };
    foo(f);

    return 0;
}

void foo (struct Foo f)
{
    printf("%d", f.y);
}

当定义和声明在不同的翻译单位之间展开时,可以更清楚,但上述情况必须这样做。

所以我建议你,在将它们用于函数原型(通过指针或值)之前,你总是在单独的行上声明你的结构。并且在真正需要之前不要引入完整的定义。

1 fa.linux.kernel上的一个可爱的信件,其中Linus Torvalds比我更清楚地说明为什么你更喜欢使用完整的struct标签。

答案 2 :(得分:1)

您的问题不是前向宣布与非前瞻宣称,而是struct Xtypedef struct { ... } X

您可以仅使用struct X解决此问题:

struct Foo;

struct Bar
{
    int x;
};

void foo (struct Foo *);
void bar (struct Bar *);

struct Foo
{
    int y;
};

完成后,您可以引入typedef名称:

typedef struct Foo Foo;

typedef struct
{
    int x;
}
Bar;

void foo (Foo *);
void bar (Bar *);

struct Foo
{
    int y;
};

您无法预先声明typedef,因此我们仍需要我们可以转发的真实struct类型。这里有一个小的不一致:Foostruct Foo相同,但没有struct Bar,只有Bar。你可以通过切换到

来解决这个问题
typedef struct Bar
{
    int x;
}
Bar;

同时定义struct BarBar

答案 3 :(得分:-1)

C支持的唯一“前向声明”和引用是指针,例如:

void myFunc (struct XYZ *p);

这告诉编译器你指的是一个类型struct XYZ,可能还没有声明,你要传递一个指针。这允许编译器在不知道该结构实际​​包含的内容的情况下执行类型检查。

请注意,指针大小都相同,因此不会检查指针本身,只检查它指向的东西。

另请参阅使用typedef解释的其他解决方案。

答案 4 :(得分:-2)

混合前向声明和类型定义。两者都是不同的东西。如果你想使用前向声明的结构的相同类型的用法:

struct Foo;             // forward declaration
struct Bar { int x; };  // definition

void foo(struct Foo);   // works for a prototype
void bar(struct Bar);   // works for a prototype

您无法转发声明类型定义。也许这就是名称​​定义的原因。但是,您可以键入define forward forward:

struct Foo;                // forward declaration
typedef struct Foo Foo_t;  // type definition of a forward declaration
struct Bar { int x; };     // definition
typedef struct Bar Bar_t;  // type definition of a definition

void foo(Foo_t);           // works
void bar(Bar_t);           // works

如果您有一个功能定义,则必须完成该类型。这意味着您已经在此位置定义了前向声明的类型,或者您必须使用指针。再说一遍:无论你使用结构还是类型定义都没关系。

顺便说一句:正如你在我的例子中所看到的那样,城市传说中不完整的结构类型必须通过“引用”传递。您可以在函数声明(原型)中使用不完整类型。但是,当您定义函数时,必须完成类型。在大多数情况下,这都不成交。