冗长的符号很重要的一次是序列在函数内部的位置,并且在函数外部也定义了一个类型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; 行表示“忘记任何以前的struct foo 类型;在此范围内有一个新类型”。当然,健忘只会持续范围。
在函数中注释掉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指的是函数外部定义的类型,因此该结构包含指向外部struct foo指针的指针数组,并且该结构有成员 data 和 example,而不是成员 array 和 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] 仍然指代外部struct foo — 您会收到相同的错误消息。
简短的道德是“不要在函数内部重新定义结构类型”。
如果必须这样做,请注意它只能在函数中真正使用;很难将它传递给其他函数 — 并非完全不可能,但您确实必须知道自己在做什么。
更长的道德是“偶尔,在可疑的情况下,struct foo; 行本身可能是至关重要的”。
请注意,即使结构体定义实际上相同,但从技术上讲,它们是不同的类型(尽管两者都称为struct foo)。这让每个人都感到困惑——请不要这样做!实际上,让我们更加迫切:
别这样!