我多次遇到这样的代码,似乎无法掌握它背后的想法或必要性。我指的是为什么一些代码声明了所述名称的结构然后他们使用typedef然后再次声明结构并且只添加结构的内容?一个例子如下:
struct foo;
typedef struct foo *foobar;
struct foo {
void *data;
foobar example[];
};
这个声明是不是没有必要,不能如下吗?
typedef struct foo *foobar;
struct foo {
void *data;
foobar example[];
};
答案 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 foo
和data
,而不是成员example
和array
。
正如我所说,这是令人震惊的风格。所以,你说&#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;
)。这让每个人都感到困惑 - 请不要这样做!实际上,让我们更加迫切:
不要这样做!