我是C编程的初学者,但我想知道在定义结构时使用typedef与不使用typedef之间有什么区别。在我看来,这两者并没有什么区别,它们实现的目标是一样的。

struct myStruct{
    int one;
    int two;
};

vs.

typedef struct{
    int one;
    int two;
}myStruct;

当前回答

不同之处在于使用结构体时。

第一种方法是:

struct myStruct aName;

第二种方法允许您删除关键字struct。

myStruct aName;

其他回答

Struct和typedef是两个完全不同的东西。

struct关键字用于定义或引用结构类型。例如,这个:

struct foo {
    int n;
};

创建名为struct foo的新类型。foo是一个标签;只有当它前面紧跟struct关键字时,它才有意义,因为标记和其他标识符位于不同的名称空间中。(这类似于c++的名称空间概念,但限制更大。)

类型定义(typedef),尽管有这个名字,但并不定义一个新的类型;它只是为现有类型创建一个新名称。例如,给定:

typedef int my_int;

My_int是int的新名称;My_int和int是完全相同的类型。类似地,给定上面的结构体定义,你可以这样写:

typedef struct foo foo;

该类型已经有一个名称,struct foo。typedef声明为同一类型赋予了一个新名称foo。

语法允许你将struct和typedef组合成一个声明:

typedef struct bar {
    int n;
} bar;

这是一个常用的习语。现在你可以把这个结构类型称为struct bar或者bar。

注意,typedef名称直到声明结束才可见。如果结构体包含指向自身的指针,则必须使用结构体版本来引用它:

typedef struct node {
    int data;
    struct node *next; /* can't use just "node *next" here */
} node;

有些程序员会为struct标记和typedef名称使用不同的标识符。在我看来,这并没有什么好理由;使用相同的名字是完全合法的,而且更清楚地表明他们是同一类型的人。如果你必须使用不同的标识符,至少使用一致的约定:

typedef struct node_s {
    /* ... */
} node;

(Personally, I prefer to omit the typedef and refer to the type as struct bar. The typedef saves a little typing, but it hides the fact that it's a structure type. If you want the type to be opaque, this can be a good thing. If client code is going to be referring to the member n by name, then it's not opaque; it's visibly a structure, and in my opinion it makes sense to refer to it as a structure. But plenty of smart programmers disagree with me on this point. Be prepared to read and understand code written either way.)

(c++有不同的规则。给定结构体blah的声明,即使没有类型定义,也可以直接将类型引用为blah。使用typedef可能会让你的C代码更像c++——如果你认为这是件好事的话。)

不同之处在于使用结构体时。

第一种方法是:

struct myStruct aName;

第二种方法允许您删除关键字struct。

myStruct aName;

在C语言中,结构、联合和枚举的类型说明关键字是强制性的,也就是说,当引用类型时,你总是必须在类型名(它的标记)前面加上struct、联合或enum。

您可以通过使用typedef来摆脱关键字,这是一种信息隐藏的形式,因为在声明对象时,对象的实际类型将不再可见。

因此建议(参见Linux内核编码风格指南,第5章)只在以下情况下这样做 实际上,您希望隐藏这些信息,而不仅仅是为了节省一些按键。

你应该使用typedef的一个例子是不透明类型,它只与相应的访问器函数/宏一起使用。

如果使用struct而不使用typedef,则总是需要编写

struct mystruct myvar;

写字是违法的

mystruct myvar;

如果使用typedef,就不再需要结构体前缀了。

常用的习语是两者都用:

typedef struct S { 
    int x; 
} S;

它们是不同的定义。为了使讨论更清楚,我将把句子分开:

struct S { 
    int x; 
};

typedef struct S S;

在第一行中,您在结构名称空间(不是c++意义上的)中定义标识符S。你可以使用它并通过将参数的类型定义为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函数之后,编译器不能自动解析结构体S,要创建该类型的对象或定义实参,必须返回到包含struct关键字:

// previous code here...
int main() {
    S(); 
    struct S s;
}