【发布时间】:2010-07-16 08:47:00
【问题描述】:
我很想知道 typedef 究竟是如何工作的。
typedef struct example identifier;
identifier x;
在上面的语句中,'标识符'只是在代码中用'结构示例'替换(比如字符串替换)?如果不是,typedef 在这里做什么?
请指教!
【问题讨论】:
我很想知道 typedef 究竟是如何工作的。
typedef struct example identifier;
identifier x;
在上面的语句中,'标识符'只是在代码中用'结构示例'替换(比如字符串替换)?如果不是,typedef 在这里做什么?
请指教!
【问题讨论】:
不,它不是字符串替换 - 那将是宏。它为该类型创建一个别名。
typedefs are preferred over macros 用于自定义类型,部分原因是它们可以正确编码指针类型。
typedef char *String_t;
#define String_d char *
String_t s1, s2;
String_d s3, s4;
s1、s2、s3都被声明为char *,而s4被声明为char,这可能不是本意。
【讨论】:
typedef 为类型引入了一个同义词。这不是简单的字符串替换,如下所示:
typedef int* int_ptr;
const int* a; // pointer to const int
const int_ptr b; // const pointer to int
编译器也知道它是一个类型名称,你不能把它放在不允许类型的地方而不会出现编译器错误。
【讨论】:
所有人都同意它不是类型替换,并且当指针进入混合时它比它好得多,但也有其他微妙之处。特别是 typedef 的使用会影响代码的解析方式和程序的有效性。
在 C 和 C++ 中,用户定义的标识符都保存在不同的名称空间中(不是 C++ 意义上的,而是某种标识符空间)。当您使用 typedef 关键字时,您为函数所在的全局名称空间中的类型创建别名。
// C/C++
struct test {};
void test( struct test x ) {} // ok, no collision
// C/C++
typedef struct test {} test; // test is now both in types and global spaces
//void test() {} // compiler error: test is a typedef, cannot be redefined
这里的细微差别是,在 C++ 中,编译器首先会在 全局命名空间 中查找,如果在那里找不到,它也会在类型命名空间中查找:
// C
struct test {};
//void f( test t ); // error, test is not defined in the global namespace
void f( struct test t ); // ok, we are telling the compiler where to look
// C++
struct test {};
void f( test t ); // ok, no test defined in the global name space,
// the compiler looks in the types name space
void g( struct test t ); // also ok, even if 'struct' not needed here.
但这并不意味着这两个命名空间合并了,只是查找会在这两个地方进行搜索。
【讨论】:
一个重要的区别是typedefs 有范围。
以下是常用的成语
class Foo: public Bar
{
private:
typedef Bar inherited;
public:
Foo(int x) : inherited(x) {}; // preferred to 'Bar(x)'
}
您通常会在 .cpp 文件中定义构造函数,并在标题中声明。如果您使用Foo(int x) : Bar(x),如果您更改类层次结构,例如 Foo->Wibble->Bar 而不是 Foo->Bar,那么您很可能会忘记更新构造函数。我个人建议将“继承”的 typedef 添加到每个子类中。
更多详情请看这里:Using "super" in C++
【讨论】:
some_template<a, other_template<b>::type, /* ... more? */>继承。
Typedef 是为(通常是复杂的)类型创建新名称的快捷方式。它的目的比预处理器的字符串替换更窄。因此,它比预处理器定义(递归解析)更不容易出错。
【讨论】:
使用 typedef 可以创建别名。编译器将别名替换为正确的代码。
如果你写:
typedef int company_id;
company_id mycompany = 100;
编译器得到:
int mycompany = 100;
【讨论】:
company_id。
宏由预处理器完成,纯粹基于文本替换。因此,您可以说他们非常愚蠢。预处理器将接受几乎所有垃圾而无需任何语法检查。
Typedef 由编译器自己完成,它们通过添加您定义的派生类型来操作编译器自己的类型表。这受制于完整的语法检查,以及专门针对类型的机制。
您可以认为编译器在执行与声明struct 时类似的“工作”。那里有一个定义,编译器将其转换为类型列表中的一个类型。
【讨论】:
我发现 typedef 使函数签名更易于阅读。假设您要返回一个指向二维数组的指针。这是可读的方式:
typedef int three_by_three[3][3];
three_by_three* foo();
下面是你如何在没有 typedef 的情况下做到这一点:
int (*bar())[3][3];
请注意,此签名与应用“字符串替换”的第一个版本完全不同。
如果 C 声明符语法不是那么难看(Stroustrup:“我认为 C 声明符语法是一个失败的实验”),typedef 可能不会像现在这样被使用。
【讨论】: