typedef struct vs struct definitions

use*_*514 763 c struct typedef

我是C编程的初学者,但我想知道typedef在定义结构时使用与使用结构之间有什么区别typedef.在我看来,实际上没有区别,他们实现了同样的目标.

struct myStruct{
    int one;
    int two;
};
Run Code Online (Sandbox Code Playgroud)

typedef struct{
    int one;
    int two;
}myStruct;
Run Code Online (Sandbox Code Playgroud)

Dav*_*eas 959

常见的习语是同时使用:

typedef struct X { 
    int x; 
} X;
Run Code Online (Sandbox Code Playgroud)

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

struct S { 
    int x; 
};

typedef struct S S;
Run Code Online (Sandbox Code Playgroud)

在第一行中,您将S在结构名称空间中定义标识符(而不是在C++意义上).您可以使用它并通过将参数的类型定义为struct S:定义新定义类型的变量或函数参数:

void f( struct S argument ); // struct is required here
Run Code Online (Sandbox Code Playgroud)

第二行在S全局名称空间中添加了一个类型别名,因此您只需编写:

void f( S argument ); // struct keyword no longer needed
Run Code Online (Sandbox Code Playgroud)

请注意,由于两个标识符名称空间不同,S因此在结构和全局空间中定义它们都不是错误,因为它不重新定义相同的标识符,而是在不同的位置创建不同的标识符.

为了使差异更清楚:

typedef struct S { 
    int x; 
} T;

void S() { } // correct

//void T() {} // error: symbol T already defined as an alias to 'struct S'
Run Code Online (Sandbox Code Playgroud)

您可以定义具有相同结构名称的函数,因为标识符保存在不同的空格中,但是您无法定义与typedef这些标识符碰撞时具有相同名称的函数.

在C++中,它略有不同,因为定位符号的规则已经巧妙地改变了.C++仍保留两个不同的标识符空间,但与C不同,当您只在类标识符空间中定义符号时,不需要提供struct/class关键字:

 // C++
struct S { 
    int x; 
}; // S defined as a class

void f( S a ); // correct: struct is optional
Run Code Online (Sandbox Code Playgroud)

搜索规则有哪些变化,而不是定义标识符的位置.编译器将搜索全局标识符表,并且在S未找到之后,它将S在类标识符内搜索.

之前呈现的代码行为方式相同:

typedef struct S { 
    int x; 
} T;

void S() {} // correct [*]

//void T() {} // error: symbol T already defined as an alias to 'struct S'
Run Code Online (Sandbox Code Playgroud)

S第二行中定义函数之后,编译器无法自动解析struct S,并且要创建对象或定义该类型的参数,您必须回退到包含struct关键字:

// previous code here...
int main() {
    S(); 
    struct S s;
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案告诉我为什么我想要typedef,所以它不能被覆盖为函数,谢谢:) (37认同)
  • 这个答案解释了编译器是如何工作的,并且使用`typedef`是一个好主意 - 但是,它并没有解释为什么在使用`typedef`-only形式的声明时应该给`struct`一个名字(第二个例子in问题).这也是我失去了大约15年的C/C++编程失败的地方,也是我所学过的最重要的信息:_"只是总是使用`typedef`; 不使用它是屁股的痛苦"_. (10认同)
  • @AlexanderVarwijk:你想要`typedef`来避免使用`struct`或`enum`进行限定.如果您使用的命名约定允许使用相同名称的函数和类型,那么您可以做的最好的方法是查看如何命名程序元素. (9认同)
  • @ SlippD.Thompson在结构名称空间中赋予`struct`一个名称的原因是它可能是前向声明的.`typedef`-只为匿名`struct`创建一个别名,这不能被前向声明.http://stackoverflow.com/a/612350/2757035 (7认同)
  • @panzi:我无法想到任何缺点,相反,如果type和typename具有相同的名称,它可能对其他用户更有意义. (4认同)
  • 赋予类型与`struct`或`enum`相同的名称是否有任何缺点?例如,如果你编写一个lib并想要简洁的类型名称,并且不想为底层结构和枚举考虑不同的名称.某些结构可能没有公开定义(它们只能通过指针访问),只有(将会)记录的类型定义名称. (2认同)

Kei*_*son 121

struct并且typedef是两个非常不同的东西.

所述struct关键字被用来定义,或指代,结构类型.例如,这个:

struct foo {
    int n;
};
Run Code Online (Sandbox Code Playgroud)

创建一个名为的新类型struct foo.这个名字foo是一个标签 ; 只有当它紧跟在struct关键字之后才有意义,因为标签和其他标识符位于不同的名称空间中.(这与namespaces 的C++概念相似,但更为局限.)

A typedef,尽管名称,但没有定义新类型; 它只是为现有类型创建一个新名称.例如,给定:

typedef int my_int;
Run Code Online (Sandbox Code Playgroud)

my_int是一个新名称int; my_int并且int完全相同的类型.同样,根据struct上面的定义,您可以写:

typedef struct foo foo;
Run Code Online (Sandbox Code Playgroud)

该类型已有名称,struct foo.该typedef声明给出了同样类型的新名称,foo.

语法允许您将a structtypedef一个声明组合在一起:

typedef struct bar {
    int n;
} bar;
Run Code Online (Sandbox Code Playgroud)

这是一个常见的习语.现在,您可以将此结构类型称为as struct bar或as bar.

请注意,typedef名称在声明结束前不可见.如果结构包含指向自身的指针,则可以使用该struct版本来引用它:

typedef struct node {
    int data;
    struct node *next; /* can't use just "node *next" here */
} node;
Run Code Online (Sandbox Code Playgroud)

一些程序员将使用不同的标识符作为struct标签和typedef名称.在我看来,没有充分的理由; 使用相同的名称是完全合法的,并使它们更清楚,它们是相同的类型.如果必须使用不同的标识符,至少使用一致的约定:

typedef struct node_s {
    /* ... */
} node;
Run Code Online (Sandbox Code Playgroud)

(就个人而言,我更喜欢省略typedef并将类型称为struct bar.typedef保存一点点输入,但它隐藏了它是一种结构类型的事实.如果你想要类型不透明,这可能是一件好事.如果客户端代码n将按名称引用成员,然后它不是不透明的;它显然是一个结构,在我看来将它称为结构是有意义的.但是很多聪明的程序员在这一点上不同意我的观点.准备阅读和理解以任何一种方式编写的代码.)

(C++有不同的规则.给定声明,即使没有typedef struct blah,你也可以引用类型blah.使用typedef可能会使你的C代码更像C++ - 就像 - 如果你认为这是一件好事.)

  • 这个答案帮助我更好地理解为什么C89库和Linux内核更可能使用`struct mystruct_t {}`而不是`typedef struct {} mystruct_t`. (3认同)
  • @RobertSsupportsMonicaCellio 您无法在没有标签的情况下进行前向声明。链接注释中的示例使用了 typedef *和* 标签。不,我的意思是使用 typedef 可以使 C 代码更像 C++。在 C++ 中,结构(以及类、联合和枚举)使用作为单个标识符的名称来引用。将类型称为“struct foo”更像是 C 语言。 (3认同)

R S*_*hko 89

另一个没有指出的区别是给结构命名(即struct myStruct)也可以让你提供结构的前向声明.所以在其他文件中,您可以写:

struct myStruct;
void doit(struct myStruct *ptr);
Run Code Online (Sandbox Code Playgroud)

无需访问定义.我建议你将两个例子结合起来:

typedef struct myStruct{
    int one;
    int two;
} myStruct;
Run Code Online (Sandbox Code Playgroud)

这为您提供了更简洁的typedef名称的便利,但仍然允许您在需要时使用完整的结构名称.

  • 有多种方法可以使用 typedef 进行前向声明:`typedef struct myStruct myStruct;`; 然后(稍后):`struct myStruct { ... };`。您可以将其用作*“struct myStruct”*或*在“typedef”之后仅使用“myStruct”(但在定义之前该类型是不完整的)。 (2认同)

Meh*_*ari 55

在C(而不是C++)中,您必须声明结构变量,如:

struct myStruct myVariable;
Run Code Online (Sandbox Code Playgroud)

为了能够使用myStruct myVariable;,您可以typedef使用结构:

typedef struct myStruct someStruct;
someStruct myVariable;
Run Code Online (Sandbox Code Playgroud)

您可以将struct定义和typedefs 组合在一个声明匿名struct和声明的语句中typedef.

typedef struct { ... } myStruct;
Run Code Online (Sandbox Code Playgroud)

  • dribeas:我在句子中涵盖了这个微妙的区别"......一个声明**匿名结构**的单一声明......" (4认同)
  • @ anthony-arnold:恩......我想我已经提到了.在一种情况下,有一个带有名称和别名的类型,另一种情况下只有一个别名.哪里重要?很简单,但如果你有一个匿名类型,你不能做`struct T x;`来声明一个变量,或者为不同类型的符号重用这个名字:`typedef struct {} f; void f(); struct fx;`在最后两个语句中失败.当然,不建议使用这样的代码(类型和具有相同名称的函数?) (3认同)
  • 接受的答案并没有很好地对比"struct"和"typedef struct",这个答案清楚地表明我使用了"typedef struct"技术,所以C可以模拟C++,以便在使用时省略"struct"传递它时的结构就像数据类型一样. (2认同)

RED*_*AIR 31

如果你struct没有使用typedef,你总是要写

struct mystruct myvar;
Run Code Online (Sandbox Code Playgroud)

写这是非法的

mystruct myvar;
Run Code Online (Sandbox Code Playgroud)

如果您使用,typedef则不再需要struct前缀.

  • 我的答案不再是最新的.当前的编译器对"typedef struct"和"struct"的处理方式相同.两者都可以在没有"struct"前缀的情况下被引用.即VC2013就是这样的. (5认同)
  • @REDSOFTADAIR *“当前编译器将“`typedef struct`”和“`struct`”视为相同。两者都可以在没有“`struc`”前缀的情况下引用。”* - 请注意,此语句不适用于 C,它是仅适用于 C++,与具体实现的作用无关。https://godbolt.org/z/XzFFv6 (5认同)

Chr*_*oph 23

在C中,结构,联合和枚举的类型说明符关键字是必需的,即您始终必须在类型的名称(其标记)前面加上struct,union或者enum在引用类型时.

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

因此,建议(例如,参见Linux内核编码样式指南,第5章)仅在您确实隐藏此信息时执行此操作,而不仅仅是保存几个键击.

应该使用a的示例typedef是opaque类型,它只与相应的访问器函数/宏一起使用.

  • Linux内核编码风格指南供参考:http://www.kernel.org/doc/Documentation/CodingStyle (4认同)
  • Linux内核编码样式文档已移至https://www.kernel.org/doc/Documentation/process/coding-style.rst (4认同)

Pla*_*mer 8

以下代码使用别名创建匿名结构myStruct:

typedef struct{
    int one;
    int two;
} myStruct;
Run Code Online (Sandbox Code Playgroud)

如果没有别名,则无法引用它,因为您没有为结构指定标识符.


Yoc*_*mer 7

你不能使用前向声明typedef struct.

struct本身是一个匿名类型,因此您没有实际名称来转发声明.

typedef struct{
    int one;
    int two;
} myStruct;
Run Code Online (Sandbox Code Playgroud)

这样的前瞻性声明不起作用:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
Run Code Online (Sandbox Code Playgroud)


RC.*_*RC. 6

与其他构造typedef一样,用于为数据类型提供新名称。在这种情况下,这样做主要是为了使代码更简洁:

struct myStruct blah;
Run Code Online (Sandbox Code Playgroud)

myStruct blah;
Run Code Online (Sandbox Code Playgroud)


jjn*_*guy 5

当你使用时,差异就在于struct.

你要做的第一种方式:

struct myStruct aName;
Run Code Online (Sandbox Code Playgroud)

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

myStruct aName;
Run Code Online (Sandbox Code Playgroud)