结构声明两次

时间:2017-10-23 05:06:00

标签: c struct

我多次遇到这样的代码,似乎无法掌握它背后的想法或必要性。我指的是为什么一些代码声明了所述名称的结构然后他们使用typedef然后再次声明结构并且只添加结构的内容?一个例子如下:

struct foo;
typedef struct foo *foobar;

struct foo {
    void *data;
    foobar example[];
};

这个声明是不是没有必要,不能如下吗?

typedef struct foo *foobar;

struct foo {
    void *data;
    foobar example[];
};

3 个答案:

答案 0 :(得分:3)

您需要先定义一个typedef才能引用它。 (另外,有一种思想学派不鼓励使用指针typedef,但这绝对是一种惯例。)

通常人们会看到"前进"在struct本身包含指向其自身的其他实例的指针的情况下,或者更通常地相互引用的结构集的情况下,结构的typedef。例如:

typedef struct foo_s foo;
struct foo_s {
    int val;
    foo *next;
};

当然,您可以始终在结构定义中使用结构标记,即struct foo_s,但如果希望一致地使用typedef foo,则需要在结构是定义的。

答案 1 :(得分:1)

他们不一样。你的第一个建议,

struct foo {
    void *data;
    foobar example[];
};

typedef struct foo *foobar;

的产率:

error: unknown type name 'foobar'
     foobar example[];
     ^

和你的第二个,

typedef struct foo {
    void *data;
    foobar example[];
} *foobar;

的产率:

error: unknown type name 'foobar'
     foobar example[];
     ^

您必须在定义之前声明。原始方式有效,因为两者

struct foo;

typedef struct foo *foobar;

是不是定义的声明。需要使用这种“非定义声明”来使相互递归的名称引用起作用。

正如评论中所指出的那样(感谢@melpomene),struct foo;声明实际上并不是必需的。

答案 2 :(得分:0)

有一段时间,冗长的符号很重要的是序列在函数内部,并且在函数外部定义了类型struct foo。然后,普通struct foo;行会影响函数外的定义。如果你不包含那一行,你可能会在看起来相同的结构中得到不兼容的指针类型,这两种类型都被称为foobar,导致可怕的混乱。 (另请参阅Which part of the C standard allows this code to compile?Does the C standard consider that there are one or two 'struct uperms_entry' types in this header?以获取更多示例。)

什么?你对我说的话感到困惑?好;这是一个例子。注意这是做作的;在函数内重新定义结构类型是不好的风格(问题的例子取决于你这样做)。

#include <stdlib.h>

struct foo;      // This line is optional; it is harmless if omitted
typedef struct foo *foobar;

struct foo
{
    void *data;
    foobar example[];  // Flexible array member; array of pointers.
};

extern void some_function(void);

void some_function(void)
{
    struct foo;     // This line is crucial!
    typedef struct foo *foobar;

    struct foo
    {
        foobar *array[3];
        void *pointer;
    };
    foobar x = calloc(sizeof(*x), 1);
    foobar y = malloc(sizeof(*y));
    y->array[0] = x->array[1];
    y->array[1] = x->array[2];
    y->array[2] = x->array[0];
    y->pointer  = x->array[1];

    free(x);
    free(y);
}

使用函数中的struct foo;行,代码可以干净地编译:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -pedantic -c st97.c
$

函数内的struct foo;行说明&#34;忘记以前的任何struct foo类型;在这个范围内有一个新的&#34;。当然,健忘只能在范围内进行。

在函数中注释掉struct foo;行,代码无法编译:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -pedantic -c st97.c
st97.c: In function ‘some_function’:
st97.c:28:6: error: ‘struct foo’ has no member named ‘array’
     y->array[0] = x->array[1];
      ^~
st97.c:28:20: error: ‘struct foo’ has no member named ‘array’
     y->array[0] = x->array[1];
                    ^~
st97.c:29:6: error: ‘struct foo’ has no member named ‘array’
     y->array[1] = x->array[2];
      ^~
st97.c:29:20: error: ‘struct foo’ has no member named ‘array’
     y->array[1] = x->array[2];
                    ^~
st97.c:30:6: error: ‘struct foo’ has no member named ‘array’
     y->array[2] = x->array[0];
      ^~
st97.c:30:20: error: ‘struct foo’ has no member named ‘array’
     y->array[2] = x->array[0];
                    ^~
st97.c:31:6: error: ‘struct foo’ has no member named ‘pointer’
     y->pointer  = x->array[1];
      ^~
st97.c:31:20: error: ‘struct foo’ has no member named ‘array’
     y->pointer  = x->array[1];
                    ^~
$

在函数内部定义类型foobar时,名称struct foo引用函数外部定义的类型,因此结构包含指向外部{的指针的数组。 {1}},该结构包含成员struct foodata,而不是成员examplearray

正如我所说,这是令人震惊的风格。所以,你说&#34;如果我在函数的结构定义中使用pointer怎么办:

struct foo

这仍然是一个问题。内部#include <stdlib.h> struct foo; typedef struct foo *foobar; struct foo { void *data; foobar example[]; // Flexible array member; array of pointers. }; extern void some_function(void); void some_function(void) { //struct foo; typedef struct foo *foobar; struct foo { struct foo *array[3]; void *pointer; }; foobar x = calloc(sizeof(*x), 1); foobar y = malloc(sizeof(*y)); y->array[0] = x->array[1]; y->array[1] = x->array[2]; y->array[2] = x->array[0]; y->pointer = x->array[1]; free(x); free(y); } struct foo之前尚未完成,因此}仍然引用外部struct foo *example[3] - 您会收到相同的错误消息。

短道德是&#34;不要重新定义函数内的结构类型&#34;。

如果必须这样做,请注意它只能在函数中使用;很难将它传递给其他功能 - 不是很不可能,但你真的必须知道你在做什么。

道德越久,偶尔,在可疑的情况下,struct foo线本身就是至关重要的&#34;。

请注意,即使结构体定义实际上是相同的,从技术上讲,它们也是不同的类型(尽管都称为struct foo;)。这让每个人都感到困惑 - 请不要这样做!实际上,让我们更加迫切:

  

不要这样做!