我是 C 编程的初学者,但我想知道在定义结构时使用typedef
与不使用typedef
什么区别。在我看来,它们之间并没有什么区别,它们实现了相同的目标。
struct myStruct{
int one;
int two;
};
与
typedef struct{
int one;
int two;
}myStruct;
常见用法同时使用:
typedef struct S {
int x;
} S;
它们是不同的定义。为了使讨论更加清晰,我将拆分句子:
struct S {
int x;
};
typedef struct S S;
在第一行中,您将在结构名称空间中定义标识符S
(不是 C ++ 含义)。您可以使用它并通过将参数的类型定义为struct S
来定义新定义类型的变量或函数参数:
void f( struct S argument ); // struct is required here
第二行在全局名称空间中添加类型别名S
,从而使您可以编写:
void f( S argument ); // struct keyword no longer needed
请注意,由于两个标识符名称空间都不同,因此在结构和全局空间中定义S
都不是错误,因为它不是重新定义相同的标识符,而是在不同的位置创建不同的标识符。
为了使区别更加清楚:
typedef struct S {
int x;
} T;
void S() { } // correct
//void T() {} // error: symbol T already defined as an alias to 'struct S'
您可以定义一个具有相同结构名称的函数,因为标识符保留在不同的空间中,但是您不能定义一个与typedef
相同名称的函数,因为这些标识符会发生冲突。
在 C ++ 中,由于定位符号的规则已经微妙地改变了,因此它略有不同。 C ++ 仍然保留两个不同的标识符空间,但是与 C 语言不同,当您仅在类标识符空间中定义符号时,不需要提供 struct / class 关键字:
// C++
struct S {
int x;
}; // S defined as a class
void f( S a ); // correct: struct is optional
什么是搜索规则更改,而不是定义标识符的位置。编译器将搜索全局识别符表后S
尚未发现它会搜索S
的类标识符内。
前面提供的代码的行为方式相同:
typedef struct S {
int x;
} T;
void S() {} // correct [*]
//void T() {} // error: symbol T already defined as an alias to 'struct S'
在第二行中定义了S
函数之后,编译器将无法自动解析 struct S,要创建对象或定义该类型的参数,您必须使用struct
关键字:
// previous code here...
int main() {
S();
struct S s;
}
struct
和typedef
是两个非常不同的东西。
struct
关键字用于定义或引用结构类型。例如,这:
struct foo {
int n;
};
创建一个名为struct foo
的新类型。名称foo
是一个标签 ;仅当它紧跟在struct
关键字之后,它才有意义,因为标记和其他标识符位于不同的名称空间中 。 (这与namespace
s 的 C ++ 概念相似,但比其受限制得多。)
尽管有名称,但typedef
并未定义新的类型。它只是为现有类型创建一个新名称。例如,给定:
typedef int my_int;
my_int
是int
的新名称; my_int
和int
是完全相同的类型。类似地,给定上面的struct
定义,您可以编写:
typedef struct foo foo;
该类型已经有一个名称, struct foo
。 typedef
声明为相同类型提供了一个新名称foo
。
该语法允许您将struct
和typedef
合并为一个声明:
typedef struct bar {
int n;
} bar;
这是一个常见的成语。现在,您可以将此结构类型称为struct bar
或称为bar
。
请注意,直到声明末尾,typedef 名称才变得可见。如果结构包含指向其自身的指针,则可以使用struct
版本来引用它:
typedef struct node {
int data;
struct node *next; /* can't use just "node *next" here */
} node;
一些程序员将为 struct 标记和 typedef 名称使用不同的标识符。我认为,这没有充分的理由。使用相同的名称是完全合法的,并且更清楚地表明它们是同一类型。如果必须使用其他标识符,请至少使用一致的约定:
typedef struct node_s {
/* ... */
} node;
(就我个人而言,我更喜欢省略typedef
并将该类型称为struct bar
typedef
节省了一些类型,但它掩盖了它是结构类型的事实。如果您希望该类型是不透明的,那么这可能是一个很好的选择。如果客户端代码要按名称引用成员n
,则它不是不透明的;它显然是一个结构,在我看来,将其称为结构是有意义的,但是许多聪明的程序员不同意我的看法。就这一点而言,请准备好阅读和理解以任何方式编写的代码。)
(C ++ 有不同的规则。给定一个struct blah
声明,即使没有 typedef,您也可以将类型引用为blah
。使用 typedef 可能会使您的 C 代码更像 C ++ -如果您认为这很好事情。)
没有指出的另一个区别是,给该结构命名(即 struct myStruct)还使您能够提供该结构的前向声明。因此,在其他文件中,您可以编写:
struct myStruct;
void doit(struct myStruct *ptr);
无需访问定义。我建议您结合两个示例:
typedef struct myStruct{
int one;
int two;
} myStruct;
这为您提供了更简洁的 typedef 名称的便利,但是仍然允许您在需要时使用完整的结构名称。