首页 文章

C中的'struct'和'typedef struct'之间的区别?

提问于
浏览
720

在C中,是否有任何区别:

struct Foo { ... };

typedef struct { ... } Foo;

8 回答

  • 0

    this DDJ article中,Dan Saks解释了一个小区域,如果你没有键入你的结构(和类!),那么bug就会蔓延开来:

    如果需要,可以想象C为每个标记名称生成一个typedef,例如typedef class string string;
    不幸的是,这并不完全准确 . 我希望它很简单,但事实并非如此 . C不能为结构,联合或枚举生成这样的typedef而不引入与C的不兼容性 . 例如,假设一个C程序声明一个函数和一个名为status的结构:int status();结构状态;
    同样,这可能是不好的做法,但它是C.在这个程序中,状态(单独)指的是函数; struct status指的是类型 . 如果C确实为标记自动生成了typedef,那么当你将这个程序编译为C时,编译器会生成:typedef struct status status;
    不幸的是,这个类型名称会与函数名称冲突,程序将无法编译 . 这就是为什么C不能简单地为每个标签生成一个typedef . 在C中,标记的行为与typedef名称类似,除了程序可以声明与标记具有相同名称和相同范围的对象,函数或枚举器 . 在这种情况下,对象,函数或枚举器名称会隐藏标记名称 . 程序只能通过在标记名称前面使用关键字class,struct,union或enum(视情况而定)来引用标记名称 . 由这些关键字之一后跟标记组成的类型名称是精心设计的类型说明符 . 例如,struct status和enum month是elaborated-type-specifiers . 因此,一个包含两个的C程序:int status();结构状态;
    编译为C时的行为相同 . 仅名称状态指的是该功能 . 程序只能通过使用elaborated-type-specifier结构状态来引用类型 . 那么这如何让bug进入程序呢?考虑清单1中的程序 . 该程序定义了一个带有默认构造函数的类foo,以及一个将foo对象转换为char const *的转换运算符 . 表达式p = foo();
    在main中应该构造一个foo对象并应用转换运算符 . 随后的输出语句cout << p <<'\ n';
    应该显示类foo,但它不会 . 它显示功能foo . 出现这种令人惊讶的结果是因为程序包含清单2中所示的头文件lib.h . 此头文件定义了一个名为foo的函数 . 函数名foo隐藏了类名foo,因此main中对foo的引用是指函数,而不是类 . main只能通过使用elaborated-type-specifier来引用类,如p = class foo();
    在整个程序中避免这种混淆的方法是为类名foo添加以下typedef:typedef class foo foo;
    紧接在类定义之前或之后 . 此typedef导致类型名称foo与函数名称foo(来自库)之间发生冲突,这将触发编译时错误 . 我知道没有人实际上写这些typedef是理所当然的 . 它需要很多纪律 . 由于错误(例如清单1中的错误)的发生率可能非常小,因此很多人都不会遇到这个问题 . 但是如果软件中的错误可能导致人身伤害,那么无论错误多么不可能,您都应该编写typedef . 我无法想象为什么有人会想要在与类相同的范围内隐藏具有函数或对象名称的类名 . C中的隐藏规则是错误的,它们不应该扩展到C中的类 . 实际上,您可以纠正错误,但它需要额外的编程规则和努力,这是不必要的 .

  • 10

    C中没有区别,但是我相信C它会允许你声明struct Foo的实例而不显式地做:

    struct Foo bar;
    
  • 211

    您不能将前向声明与typedef结构一起使用 .

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

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

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

    struct myStruct; //forward declaration fails
    
    void blah(myStruct* pStruct);
    
    //error C2371: 'myStruct' : redefinition; different basic types
    
  • 60

    Struct是创建数据类型 . typedef用于设置数据类型的昵称 .

  • 1063

    在C中,只有一个微妙的区别 . 这是C的延续,它有所作为 .

    C语言标准(C89 §3.1.2.3C99 §6.2.3C11 §6.2.3)为不同类别的标识符强制命名,包括标记标识符(用于 struct / union / enum )和普通标识符(用于 typedef 和其他标识符) .

    如果你刚才说:

    struct Foo { ... };
    Foo x;
    

    您将收到编译器错误,因为 Foo 仅在标记名称空间中定义 .

    您必须将其声明为:

    struct Foo x;
    

    任何时候你想要引用 Foo ,你总是要把它称为 struct Foo . 这会很快烦人,所以你可以添加 typedef

    struct Foo { ... };
    typedef struct Foo Foo;
    

    现在 struct Foo (在标记命名空间中)和普通的 Foo (在普通标识符命名空间中)都指向相同的东西,并且您可以在没有 struct 关键字的情况下自由声明 Foo 类型的对象 .


    结构:

    typedef struct Foo { ... } Foo;
    

    只是声明的缩写和 typedef .


    最后,

    typedef struct { ... } Foo;
    

    声明一个匿名结构并为它创建一个 typedef . 因此,使用此构造,它在标记名称空间中没有名称,只有typedef名称空间中的名称 . 这意味着它也无法向前宣布 . 如果要进行前向声明,则必须在标记名称空间中为其指定名称 .


    在C中,只要名称未被具有相同名称的另一个声明隐藏,所有 struct / union / enum / class 声明就像它们隐含地一样 . 有关详细信息,请参阅Michael Burr's answer .

  • -2

    一个更重要的区别: typedef s无法向前声明 . 因此,对于 typedef 选项,您必须 #include 包含 typedef 的文件,这意味着 #include 的所有 #include 也包含该文件,无论是否直接需要它,依此类推 . 它肯定会影响您在大型项目上的构建时间 .

    如果没有 typedef ,在某些情况下,您只需在 .h 文件的顶部添加 struct Foo; 的前向声明,并在 .cpp 文件中仅添加 #include 结构定义 .

  • 0

    is 一个区别,但微妙 . 这样看: struct Foo 引入了一种新类型 . 第二个为未命名的 struct 类型创建一个名为Foo(而不是新类型)的别名 .

    7.1.3 typedef说明符1 [...]用typedef说明符声明的名称变为typedef-name . 在其声明的范围内,typedef-name在语法上等同于关键字,并按照第8章中描述的方式命名与标识符关联的类型 . 因此,typedef-name是另一种类型的同义词 . typedef-name不会像类声明(9.1)或枚举声明那样引入新类型 . 8如果typedef声明定义了一个未命名的类(或枚举),则声明声明为该类类型(或枚举类型)的第一个typedef-name用于表示类型(或枚举类型)仅用于链接目的( 3.5) . [例如:

    typedef struct { } *ps, S; // S is the class name for linkage purposes
    

    因此,typedef always 用作另一种类型的占位符/同义词 .

  • 30

    C中'typedef结构'和'结构'之间的一个重要区别是'typedef结构'中的内联成员初始化将不起作用 .

    // the 'x' in this struct will NOT be initialised to zero
    typedef struct { int x = 0; } Foo;
    
    // the 'x' in this struct WILL be initialised to zero
    struct Foo { int x = 0; };
    

相关问题