声明C结构的语法正确方法是什么?

时间:2022-08-24 22:17:05

I've seen C structs declared several different ways before. Why is that and what, if anything, does each do different?

我以前见过几种不同的C语言结构。为什么会这样,如果有什么,每个都有什么不同?

For example:

例如:

struct foo {
  short a;
  int b;
  float c;
};

typedef struct {
  short d;
  int e;
  float f;
} bar;

typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

int main (int argc, char const *argv[])
{
  struct foo a;
  bar b;
  baz c;

  return 0;
}

4 个解决方案

#1


32  

Well, the obvious difference is demonstrated in your main:

好吧,你的主要证明了明显的区别:

struct foo a;
bar b;
baz c;

The first declaration is of an un-typedefed struct and needs the struct keyword to use. The second is of a typedefed anonymous struct, and so we use the typedef name. The third combines both the first and the second: your example uses baz (which is conveniently short) but could just as easily use struct _baz to the same effect.

第一个声明是一个un-typedefed结构,需要使用struct关键字。第二个是typedefed匿名结构,因此我们使用typedef名称。第三个结合了第一个和第二个:你的例子使用baz(它很方便)但可以很容易地使用struct _baz来达到同样的效果。

Update: larsmans' answer mentions a more common case where you have to use at least struct x { } to make a linked list. The second case wouldn't be possible here (unless you abandon sanity and use a void * instead) because the struct is anonymous, and the typedef doesn't happen until the struct is defined, giving you no way to make a (type-safe) pointer to the struct type itself. The first version works fine for this use, but the third is generally preferred in my experience. Give him some rep for that.

更新:larsmans的回答提到了一个更常见的情况,你必须至少使用struct x {}来制作一个链表。第二种情况在这里是不可能的(除非你放弃了理智并改为使用void *),因为结构是匿名的,并且在定义结构之前不会发生typedef,这使得你无法做出类型 - 安全)指向结构类型本身的指针。第一个版本适合这种用途,但第三个版本在我的经验中通常是首选。给他一些代表。

A more subtle difference is in namespace placement. In C, struct tags are placed in a separate namespace from other names, but typedef names aren't. So the following is legal:

更精细的区别在于命名空间放置。在C中,struct标记放在与其他名称不同的名称空间中,但typedef名称不是。所以以下是合法的:

struct test {
  // contents
};

struct test *test() {
  // contents
}

But the following is not, because it would be ambiguous what the name test is:

但以下情况并非如此,因为名称测试的含义是不明确的:

typedef struct {
  // contents
} test;

test *test() {
  // contents
}

typedef makes the name shorter (always a plus), but it puts it in the same namespace as your variables and functions. Usually this isn't an issue, but it is a subtle difference beyond the simple shortening.

typedef使名称更短(总是加号),但它将它放在与变量和函数相同的名称空间中。通常这不是问题,但除了简单的缩短之外,它是一个微妙的差异。

#2


27  

It's largely a matter of personal preference. I like to give new types a name starting with a capital letter and omit the struct, so I usually write typedef struct { ... } Foo. That means I cannot then write struct Foo.

这主要取决于个人偏好。我喜欢给新类型一个以大写字母开头的名称并省略结构,所以我经常写一个typedef struct {...} Foo。这意味着我无法编写struct Foo。

The exception is when a struct contains a pointer to its own type, e.g.

例外情况是结构包含指向其自身类型的指针,例如

typedef struct Node {
    // ...
    struct Node *next;
} Node;

In this case you need to also declare the struct Node type, since the typedef is not in scope within the struct definition. Note that both names may be the same (I'm not sure where the underscore convention originated, but I guess older C compilers couldn't handle typedef struct X X;).

在这种情况下,您还需要声明struct Node类型,因为typedef不在struct定义的范围内。请注意,两个名称可能是相同的(我不确定下划线约定的来源,但我猜旧的C编译器无法处理typedef struct X X;)。

#3


7  

All your uses are syntactically correct. I prefer the following usage

您的所有用法在语法上都是正确的。我更喜欢以下用法

 /* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
  short a;
  int b;
  foo* next;
};

Observe that this easily allows to use the typedef already inside the declaration of the struct itself, and that even for struct that reference each other mutually.

观察到这很容易允许在结构本身的声明中使用typedef,甚至对于相互引用的结构也是如此。

#4


5  

The confusion comes about because some of the declarations are in fact declaring up to three C constructs. You need to keep in mind the difference between: 1. A typedef declaration, 2. A struct definition, and 3. A struct declaration.

之所以产生混淆,是因为有些声明实际上声明了最多三个C结构。您需要记住以下两者之间的区别:1。typedef声明,2。结构定义,以及3.结构声明。

They are all very different C constructs. They all do different things; but you can combine them into the one compound construct, if you want to.

它们都是非常不同的C结构。他们都做不同的事情;但如果您愿意,可以将它们组合成一个复合构造。

Let's look at each declaration in turn.

让我们依次看一下每个声明。

//================================================
struct foo {
  short a;
  int b;
  float c;
};

Here we are using the most basic struct definition syntax. We are defining foo as a C type that can later be used to declare variables of that type using the following syntax:

这里我们使用最基本的结构定义语法。我们将foo定义为C类型,以后可以使用以下语法来声明该类型的变量:

foo myFoo;  // Declare a struct variable of type foo.

//==================================================== This next declaration is a bit like the previous syntax in that it declares a C type, but it uses the typedef syntax. Let's break it down into its components using the previous basic declaration.

// ================================================ ====下一个声明有点像前面的语法,因为它声明了C类型,但它使用了typedef语法。让我们使用之前的基本声明将其分解为其组件。

typedef foo bar; // Declare bar as a variable type, the alias of foo.

bar myBar;       // This is ssemantically the same as: foo myBar;

Now just replace the "foo" with the previous syntax and voila!

现在只需用之前的语法替换“foo”即可!

typedef struct {
  short d;    
  int e;
  float f;
} bar;

//==================================================================
typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

The above syntax is equivalent to the following sequence of declarations.

上面的语法等同于以下声明序列。

struct _baz {
  short a;
  int b;
  float c;
}

typedef _baz baz; // Declare baz as an alias for _baz.

baz myBaz;       // Is the same as: _baz myBaz;

//========================================================

#1


32  

Well, the obvious difference is demonstrated in your main:

好吧,你的主要证明了明显的区别:

struct foo a;
bar b;
baz c;

The first declaration is of an un-typedefed struct and needs the struct keyword to use. The second is of a typedefed anonymous struct, and so we use the typedef name. The third combines both the first and the second: your example uses baz (which is conveniently short) but could just as easily use struct _baz to the same effect.

第一个声明是一个un-typedefed结构,需要使用struct关键字。第二个是typedefed匿名结构,因此我们使用typedef名称。第三个结合了第一个和第二个:你的例子使用baz(它很方便)但可以很容易地使用struct _baz来达到同样的效果。

Update: larsmans' answer mentions a more common case where you have to use at least struct x { } to make a linked list. The second case wouldn't be possible here (unless you abandon sanity and use a void * instead) because the struct is anonymous, and the typedef doesn't happen until the struct is defined, giving you no way to make a (type-safe) pointer to the struct type itself. The first version works fine for this use, but the third is generally preferred in my experience. Give him some rep for that.

更新:larsmans的回答提到了一个更常见的情况,你必须至少使用struct x {}来制作一个链表。第二种情况在这里是不可能的(除非你放弃了理智并改为使用void *),因为结构是匿名的,并且在定义结构之前不会发生typedef,这使得你无法做出类型 - 安全)指向结构类型本身的指针。第一个版本适合这种用途,但第三个版本在我的经验中通常是首选。给他一些代表。

A more subtle difference is in namespace placement. In C, struct tags are placed in a separate namespace from other names, but typedef names aren't. So the following is legal:

更精细的区别在于命名空间放置。在C中,struct标记放在与其他名称不同的名称空间中,但typedef名称不是。所以以下是合法的:

struct test {
  // contents
};

struct test *test() {
  // contents
}

But the following is not, because it would be ambiguous what the name test is:

但以下情况并非如此,因为名称测试的含义是不明确的:

typedef struct {
  // contents
} test;

test *test() {
  // contents
}

typedef makes the name shorter (always a plus), but it puts it in the same namespace as your variables and functions. Usually this isn't an issue, but it is a subtle difference beyond the simple shortening.

typedef使名称更短(总是加号),但它将它放在与变量和函数相同的名称空间中。通常这不是问题,但除了简单的缩短之外,它是一个微妙的差异。

#2


27  

It's largely a matter of personal preference. I like to give new types a name starting with a capital letter and omit the struct, so I usually write typedef struct { ... } Foo. That means I cannot then write struct Foo.

这主要取决于个人偏好。我喜欢给新类型一个以大写字母开头的名称并省略结构,所以我经常写一个typedef struct {...} Foo。这意味着我无法编写struct Foo。

The exception is when a struct contains a pointer to its own type, e.g.

例外情况是结构包含指向其自身类型的指针,例如

typedef struct Node {
    // ...
    struct Node *next;
} Node;

In this case you need to also declare the struct Node type, since the typedef is not in scope within the struct definition. Note that both names may be the same (I'm not sure where the underscore convention originated, but I guess older C compilers couldn't handle typedef struct X X;).

在这种情况下,您还需要声明struct Node类型,因为typedef不在struct定义的范围内。请注意,两个名称可能是相同的(我不确定下划线约定的来源,但我猜旧的C编译器无法处理typedef struct X X;)。

#3


7  

All your uses are syntactically correct. I prefer the following usage

您的所有用法在语法上都是正确的。我更喜欢以下用法

 /* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
  short a;
  int b;
  foo* next;
};

Observe that this easily allows to use the typedef already inside the declaration of the struct itself, and that even for struct that reference each other mutually.

观察到这很容易允许在结构本身的声明中使用typedef,甚至对于相互引用的结构也是如此。

#4


5  

The confusion comes about because some of the declarations are in fact declaring up to three C constructs. You need to keep in mind the difference between: 1. A typedef declaration, 2. A struct definition, and 3. A struct declaration.

之所以产生混淆,是因为有些声明实际上声明了最多三个C结构。您需要记住以下两者之间的区别:1。typedef声明,2。结构定义,以及3.结构声明。

They are all very different C constructs. They all do different things; but you can combine them into the one compound construct, if you want to.

它们都是非常不同的C结构。他们都做不同的事情;但如果您愿意,可以将它们组合成一个复合构造。

Let's look at each declaration in turn.

让我们依次看一下每个声明。

//================================================
struct foo {
  short a;
  int b;
  float c;
};

Here we are using the most basic struct definition syntax. We are defining foo as a C type that can later be used to declare variables of that type using the following syntax:

这里我们使用最基本的结构定义语法。我们将foo定义为C类型,以后可以使用以下语法来声明该类型的变量:

foo myFoo;  // Declare a struct variable of type foo.

//==================================================== This next declaration is a bit like the previous syntax in that it declares a C type, but it uses the typedef syntax. Let's break it down into its components using the previous basic declaration.

// ================================================ ====下一个声明有点像前面的语法,因为它声明了C类型,但它使用了typedef语法。让我们使用之前的基本声明将其分解为其组件。

typedef foo bar; // Declare bar as a variable type, the alias of foo.

bar myBar;       // This is ssemantically the same as: foo myBar;

Now just replace the "foo" with the previous syntax and voila!

现在只需用之前的语法替换“foo”即可!

typedef struct {
  short d;    
  int e;
  float f;
} bar;

//==================================================================
typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

The above syntax is equivalent to the following sequence of declarations.

上面的语法等同于以下声明序列。

struct _baz {
  short a;
  int b;
  float c;
}

typedef _baz baz; // Declare baz as an alias for _baz.

baz myBaz;       // Is the same as: _baz myBaz;

//========================================================