是一个结构{...};一个类型或一个未命名的变量?

时间:2015-08-07 12:25:11

标签: c struct

以下是文件范围,类型声明还是未命名的变量?

struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

如果是类型定义,那么有什么区别:

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

(背景:请参阅我在Changing a variable from global to local - C的回答,我相信第一个引入了一个未命名的变量,然后由编译器进行优化。)

注意:该问题已被标记为In what scope is a struct member identifier put?的可能副本,但我相信我不会询问有关成员范围的问题,而是关于声明实际创建的内容。然而。 Difference between 'struct' and 'typedef struct' in C++?的答案确实解释了我的问题。

6 个答案:

答案 0 :(得分:6)

根据C标准,形式为

的结构声明
struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

类型的声明。引用C11,章节§6.7.2.1

  

struct-or-union-specifier中struct-declaration-list的存在在转换单元中声明了一个新类型。 struct-declaration-list是结构或联合成员的一系列声明。 [...]

C标准不要求为该类型创建变量(命名或未命名)。

在您的第二个片段中,您实际上(尝试typedef没有。但是,如果您将代码段更改为

的形式
typedef struct {
         //.....members
} student_s ;

您将创建类型 student_stypedef到未命名的结构类型),稍后您可以使用它。

FWIW,我们从未谈论这里创建的变量,无论如何。这完全是关于类型

答案 1 :(得分:3)

第一个声明声明了一个类型。在声明之后,类型struct student_s是已知的,您可以声明该类型的变量或指向它的指针:

struct student_s student1;
struct student_s *pStudent;

即使编译,第二个声明也很奇怪。常见的用法是:

typedef struct {
    char* name;
    int age;
    double height;
    struct student_s* next;   
} studend_t;

向匿名结构声明别名student_t。然后可以直接使用它:

student_t student1;
student_t *pStudent;

但第二个例子是编辑(即使有警告)并且与第一个一样!

它真正做的是向struct student_s声明一个void别名。 typedef被忽略并产生警告: typedef需要一个名称,但作为一个副作用,结构被声明,就像在第一个例子中一样。

所以除了警告之外,实际问题的真正答案是没有差异

答案 2 :(得分:2)

两者都是类型定义。第二个是一个不完整的。它没有提供名称作为typedef的参数。更好的是使用

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
} student;


关于

的合法性
typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

我已经问过这个单独的问题,Legality of `typedef struct foo {int bar};`

答案 3 :(得分:1)

它是一种类型,你不能拥有一个结构的匿名实例。为了进行比较,这会声明类型为struct_type 的实例struct_instance

struct struct_type {
    /* blah */
} struct_instance;

如果你想隔离声明另一个实例(来自类型decl),你可以使用

struct struct_type another_instance;

使用typedef - 如果操作正确,与您的示例不同 - 只允许您为类型指定另一个名称,该名称不需要struct关键字来声明实例:

typedef struct_type MyStruct;
MyStruct yet_another_instance;

或等效

typedef struct struct_type {
    /* blah */
} MyStruct;

省略名称(struct_type)会为您提供一个匿名结构类型,该结构类型只能通过其typedef"名称来引用。

注1

由于您的原始结构包含指向其自身类型的next指针,因此该类型必须在声明该成员时具有名称。所以,不能使用自键型指针声明一个匿名结构。如果您为匿名结构类型指定了typedef的名称,则该名称在成员声明之后才会存在,因此无法在此处使用。

typedef struct /*S*/ {
    struct S *next; /* T doesn't exist yet, so without S, you can't declare this */
} T;

注2

可以声明一个匿名联盟的匿名实例,作为成员:

struct S {
    union {
        int i;
        unsigned u;
    };
};

struct S s;
s.i = -1;
printf("%x\n", s.u);

但这是一个非常特殊的案例。我把这个说法从主要论点中删除了,以防它误导。

答案 4 :(得分:0)

不同之处在于,对于第一个示例,您必须声明一个新变量:struct student_s variable;,但是对于第二个示例,您可以只执行student_s variable;

答案 5 :(得分:0)

struct A { ... }

创建struct' A'在struct命名空间中可见(与C ++命名空间没有任何共同之处)。因此,要访问struct,您必须使用struct关键字;

struct A a;

使用typedef struct

定义时
typedef struct A { ... } B;

变得可见并绑定到B,您可以轻松创建类似B的公共变量struct

B a;

如果我错了,请纠正我。