为什么没有' typedef struct' C中是否可选?

时间:2016-03-05 01:43:48

标签: c struct standards typedef

在C中,可以定义一个struct,typedefed,并声明为:

typedef struct {
    int bar;
} Foo;
Foo foo;

或者:

struct Foo {
    int bar;
} foo;
typedef struct Foo Foo;

我认为这有点不一致且过于冗长。我希望它能像C ++一样工作。

在C ++中,您不需要指定typedef struct Foo Foo;来声明像Foo foo;而不是struct Foo foo;这样的结构。为什么没有将它引入C标准或作为编译器标志选项?如果在C中将typedef struct作为可选项,是否有任何C代码会中断?

3 个答案:

答案 0 :(得分:8)

可选。

struct mystruct {
    int x;
};

struct mystruct y;

结构定义位于“标记”名称的单独名称空间中。这样它们就不会与函数或变量名冲突,所以你可以这样做:

struct stat st;
int r = stat("/path/file.txt", &st);

您注意到stat是函数的名称和结构的名称,但它们不会发生冲突?这是一个真实的例子,请参阅stat (2)。如果你消除了这个,旧的代码将无法编译。 typedef在与函数和变量相同的命名空间中创建名称。

struct stat { ... };
int stat(const char *path, struct stat *buf);
typedef struct stat stat; // ERROR

某些样式指南使用typedef提倡,只需在任何地方输入struct stat。无论你是否同意这一点,它都存在于各个地方(例如Linux内核!),C标准委员会反对破坏现有的C代码库。

在C ++中,通过使struct可选来维护与C代码的兼容性,但是如果定义一个与结构同名的函数,则需要在变量定义中显式使用struct: / p>

stat st; // error! stat is a function
struct stat st; // Ok
int r = stat("/path/file.txt", &st);

答案 1 :(得分:3)

嗯,你有这个:

struct Foo {
    int bar;
} foo;
typedef struct Foo Foo;

在第一行中,您将在结构名称空间中定义标识符Foo(不是在C ++意义上)。您可以使用它并通过将参数类型定义为struct Foo来定义新定义类型的变量或函数参数:

void f(struct Foo argument);

在上面的函数中,struct是必需的。 第二行在全局名称空间中添加了一个类型别名Foo,因此您只需编写:

void f(Foo argument);

在上面的函数声明中,不再需要struct关键字。请注意,由于两个标识符名称空间不同,因此在结构和全局空间中定义Foo不是错误,因为它不是重新定义相同的标识符,而是在不同的位置创建不同的标识符。

使差异更明显:

typedef struct Foo { 
    int x; 
} Bar;

void Foo() { } // correct

//void Bar() {} // error: symbol Bar already defined as an alias to 'struct Foo'

您可以定义一个具有相同结构名称的函数,因为标识符保存在不同的空格中,但是您无法定义与typedef同名的函数,因为这些标识符会发生碰撞。

所以,常见的习惯用法是:

typedef struct Foo {
    int bar;
} Foo;
Foo foo;

编辑(更多信息):

在C ++中,它略有不同,因为定位符号的规则已经巧妙地改变了。 C ++仍保留两个不同的标识符空间,但与C中不同,当您只在类标识符空间中定义符号时,不需要提供struct / class关键字。搜索规则有哪些变化,而不是定义标识符的位置。编译器将搜索全局标识符表并在' Foo'之后还没有发现它会搜索Foo'在类标识符中。

答案 2 :(得分:2)

编译器可以自由地进行扩展,但由于没有编译器 委员会没有理由将其标准化。

  

是否有任何C代码的例子,如果是typedef结构会破坏   是否可以在C?

中选择

大量。考虑类似的事情:

struct Foo {
    int bar;
    /* ... */
};

void Foo(void) {
    /* ... */
}

它将停止编译。