何为命名空间?
比如结构体的成员名和变量名不在同一命名空间中,但枚举的成员名却和变量名在同一命名空间中,所以会出现命名冲突。
命名空间(namespace) 表示标识符(identifier)的上下文(context)。 一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。 这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
在编程语言中,命名空间是一种特殊的作用域,且本身也用一个标识符来表示, 这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。 许多现代编程语言都支持命名空间。在一些编程语言(例如C++和Python)中, 命名空间本身的标识符也属于一个外层的命名空间,也即命名空间可以嵌套, 构成一个命名空间树,树根则是无名的全局名空间。
一些语言的命名空间:
<blockquote>
C++: namespace关键字
Java: 包
Python: 模块
</blockquote>
<h4>C语言的命名空间</h4>
C语言标准定义了4种命名空间:
1. label names
所有的label位于一个命名空间下;
2. the tags of structures, unions, and enumerations
全局的结构struct, 联合union 和 枚举enum,位于一个命名空间下;
3. the members of structures or unions
结构struct和联合union的成员位于它们各自struct或union命名空间下,相互独立互不影响,并且可以形成递归的命名空间(如struct中再定义struct)。
4. all other identifiers
所有其它的标识符,包括变量名、函数名、类型名(typedef)和枚举常量,位于一个命名空间下; 这里的标识符只的是全局标识符,必须通过其它文件可以访问到,局部标识符(static)不会污染这个命名空间。
因此可以看到,C语言预定义了3个全局的命名空间,并且可以通过再定义struct或union添加新的命名空间。
C语言的命名空间使得在一个大程序中,本来无关的模块,很容易使用同一名称表示不同的目的。 避免这种名称碰撞(name collision)的方法是标识符使用前缀,如模块名作为标识符的开始。
C语言的这种命名空间方式也造成了C和C++混合编程时的一些障碍,因为C++有复杂的命名空间规定,这导致在编译时对C和C++标示符的不同解析方式,这在以后再详细分析。
<h4>Tip</h4>
有一个tip是,由于结构struct和typedef类型名不在同一命名空间下, 因此诸如:
<blockquote>typedef struct Stack_T *Stack_T;</blockquote>
这样的定义一个Stack_T类型时可以的,并不会产生标识符冲突。
还有一个是以下方式并没有冲突:
<blockquote>
struct A { int a };
int A;
</blockquote>
但这在C++中却会产生冲突,这也是C++的命名空间和C不同的结果。