协慌网

登录 贡献 社区

typedef 结构与结构定义

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

struct myStruct{
    int one;
    int two;
};

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

答案

常见用法同时使用:

typedef struct S { 
    int x; 
} S;

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

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函数之后,编译器将无法自动解析 struct S,要创建对象或定义该类型的参数,您必须使用struct关键字:

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

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

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

struct foo {
    int n;
};

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

尽管有名称,但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 bar typedef节省了一些类型,但它掩盖了它是结构类型的事实。如果您希望该类型是不透明的,那么这可能是一个很好的选择。如果客户端代码要按名称引用成员n ,则它不是不透明的;它显然是一个结构,在我看来,将其称为结构是有意义的,但是许多聪明的程序员不同意我的看法。就这一点而言,请准备好阅读和理解以任何方式编写的代码。)

(C ++ 有不同的规则。给定一个struct blah声明,即使没有 typedef,您也可以将类型引用为blah 。使用 typedef 可能会使您的 C 代码更像 C ++ -如果您认为这很好事情。)

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

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

无需访问定义。我建议您结合两个示例:

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

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