我不是初学者,我对以下习语非常熟悉:
typedef struct Foo_ Foo;// I know typedef struct Foo Foo is fine, I'm just trying to make it clearer
struct Foo_
{
int value;
Foo *link;
};
我只是突然感到困惑,因为我的理解是在声明之前不允许使用名称(标识符)。但在声明typedef struct Foo_ Foo
中,标识符Foo_
尚不存在!为什么编译器允许这种情况发生?请问有人对此有所了解,向我解释这种语法的理由是什么?
维基百科引用:typedef
的目的是为现有类型指定替代名称。
---> 8 ---
感谢所有人提供了这么多有用的信息。
答案 0 :(得分:30)
这完全没问题。像您这样的struct
标记的首次使用是struct
类型的前向声明。
请注意,_Foo
的使用不符合要求。保留带有前导下划线和后跟大写字母的标识符。不要那样做。尾随下划线可以。
答案 1 :(得分:13)
这在6.7.2.3p8中有所介绍:
6.7.2.3标签
的语义强>
[...]8 - 如果形式 struct-or-union identifier 的类型说明符不是[struct-or-union definition]或[struct-or-union declaration],那么没有其他声明 标识符作为标记是可见的,然后它声明一个不完整的结构或联合类型,和 将标识符声明为该类型的标记。
struct Foo
中的类型说明符typedef struct Foo Foo
不在定义(struct Foo {...};
)或声明(struct Foo;
)中,因此它低于6.7.2.3p8。
请注意typedef
没有什么特别之处;你也可以,例如写
struct A { struct Foo *p; };
并且不需要显示先前的定义或声明。
但是,在函数声明或定义中:
void foo(struct Foo *p);
如果先前未声明struct Foo
,那么声明的范围将只是函数声明或定义,并且它不会与任何后续声明或定义类型兼容Foo
。
答案 2 :(得分:4)
ISO c99 : 6.2.1 Scopes of identifiers
7
结构,联合和枚举标记的范围在外观之后开始 声明标记的类型说明符中的标记。
typedef struct _Foo Foo; // You can do this because it's just the typedef the new type
struct _Foo *myfoo ; // It's pointer to struct _Foo (an incomplete type)
//but make sure before using myfoo->value
// struct definition should be available
struct _Foo MyFoo; // It's definition of MyFoo but don't forget
// to give the definition of struct _Foo (gcc extension).
struct _Foo; // forward declaration
struct _Foo // It's the definition
{
int value;
Foo *link;
};
就像functions
一样,我们在实际定义函数之前会forward declaration
或typedef
,所以我们也可以struct
执行此操作。
void func(int );
typedef void (*func_t)(int);
void func(int x)
{
//actual definition
}
答案 3 :(得分:3)
typedef
用于为类型创建别名。但是当typedef'ed时,这种类型不一定存在。
例如,
如果您这样做:
struct Foo;
并且你永远不会在程序中的任何地方定义struct Foo
,然后它仍然会编译。
编译器会认为它已在某处定义并继续。只有在不定义结构的情况下使用它,才会发生错误。
typedef
也是类似的情况。
答案 4 :(得分:1)
在某些情况下,在声明之前使用struct ...
类型是有效的。那就是所谓的“不完全类型”。
例如,将变量声明为指向“不完整”结构的指针以及(如您所见)typedef
是有效的。
答案 5 :(得分:1)
它被称为向前声明。前向声明允许您在允许不完整类型的上下文中使用其名称。
编译器将“看到”typedef标记,并将其存储起来,直到找到类型为止,因此只要你在typedef之后声明了类型,但在任何使用之前,它就没问题了。
答案 6 :(得分:-1)
typedef声明允许您定义自己的标识符,这些标识符可用于代替int,float和double等类型说明符。 typedef声明不保留存储空间。