提问




????这个问题在这里已有答案:

????

    ????????

  • ????????????我们为什么要在C中经常输入一个结构?
    ????????????????
    ????????????????????15个答案
    ????????????????
    ????????

  • ????

最佳参考


常见的习语是同时使用:/questions/252780/why-should-we-typedef-a-struct-so-often-in-c


typedef struct X { 
    int x; 
} X;


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


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函数之后,编译器无法自动解析结构S,并且要创建对象或定义该类型的参数,您必须回退到包含struct]]关键字:


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

其它参考1


structtypedef是两个非常不同的东西。


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


struct foo {
    int n;
};


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


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


typedef int my_int;


my_intint的新名称; my_intint 完全相同的类型。同样,鉴于上面的struct定义,你可以写:


typedef struct foo foo;


该类型已有名称,struct footypedef声明为同一类型提供了新名称foo


语法允许您将structtypedef组合成单个声明:


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 bartypedef保存一点点输入,但它隐藏了它是结构类型的事实。如果你希望类型是不透明的,这可能是一件好事。如果客户端代码将按名称引用成员n,那么它不是不透明的;它显然是一个结构,在我的认为把它称为结构是有意义的。但是很多聪明的程序员在这一点上不同意我的看法。准备阅读和理解以任何一种方式编写的代码。)


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

其它参考2


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


struct myStruct;
void doit(struct myStruct *ptr);


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


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


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

其它参考3


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


struct myStruct myVariable;


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


typedef struct myStruct someStruct;
someStruct myVariable;


你可以将struct定义和typedef结合在一个声明匿名structtypedef的单个语句中。


typedef struct { ... } myStruct;

其它参考4


在C中,结构,联合和枚举的类型说明符关键字是强制性的,即您始终必须在类型的名称(其标记)前加上structunionenum在提及类型时。


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


因此,建议(仅参见Linux内核编码样式指南,第5章)仅在执行此操作时执行此操作
你实际上想隐藏这些信息,而不仅仅是保存一些按键。[93]


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

其它参考5


如果你使用没有typedefstruct,你将永远都要写


struct mystruct myvar;


写作是违法的


mystruct myvar;


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

其它参考6


使用struct时会出现差异。


你要做的第一种方式:


struct myStruct aName;


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


myStruct aName;

其它参考7


你不能在typedef struct中使用前向声明。


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


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


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


struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

其它参考8


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


struct myStruct blah;





myStruct blah;

其它参考9


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


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


您不能在没有别名的情况下引用它,因为您没有为结构指定标识符。

其它参考10


我看到有一些澄清是为了这个。 C和C ++不以不同方式定义类型。 C ++最初只不过是C之上的另一组包含。


几乎所有C/C ++开发人员现在面临的问题是:a)大学不再教授基础知识,b)人们不了解定义和声明之间的区别。


这种声明和定义存在的唯一原因是链接器可以计算结构中字段的地址偏移量。这就是大多数人逃避实际写错的代码的原因 - 因为编译器能够确定寻址。当有人试图提前做某事时,例如队列,链表,或者支持O/S结构,就会出现问题。


声明以struct开头,定义以typedef开头。


此外,struct具有前向声明标签和定义的标签。大多数人都不知道这一点并使用前向声明标签作为定义标签。


错误:


struct myStruct
   {
   int field_1;
   ...
   };


他们只是使用前向声明来标记结构 - 所以现在编译器已经意识到了 - 但它不是一个实际定义的类型。编译器可以计算寻址 - 但这不是打算如何使用,原因我将暂时显示。


使用这种形式的声明的人,必须始终将结构放在实际的每一个引用中 - 因为它不是一种正式的新类型。


相反,任何不引用自身的结构都应该以这种方式声明和定义:


typedef struct
   {
   field_1;
   ...
   }myStruct;


现在它是一个实际的类型,当你使用时,你可以使用at作为myStruct,而不必在其前面添加struct。


如果您想要一个指向该结构的指针变量,那么请包含一个辅助标签:


typedef struct
   {
   field_1;
   ...
   }myStruct,*myStructP;


现在你有一个指向该结构的指针变量,它是自定义的。


前瞻性声明 -


现在,这里是花哨的东西,前向声明如何工作。如果你想创建一个引用自身的类型,如链接列表或队列元素,你必须使用前向声明。编译器不考虑结构定义,直到它到达最后的分号,所以它只是在那一点之前声明。


typedef struct myStructElement
   {
   myStructElement*  nextSE;
   field_1;
   ...
   }myStruct;


现在,编译器知道虽然它还不知道整个类型是什么,但它仍然可以使用前向引用来引用它。


请正确声明并输入你的结构。实际上有一个原因。

其它参考11


对于后一个示例,在使用结构时省略struct关键字。所以你的代码中到处都可以写:


myStruct a;


代替


struct myStruct a;


这节省了一些打字,可能更具可读性,但这是一个品味问题