河北邯郸网站建设,百度集团股份有限公司,网站建设结构,网站建设 怎么跑业务当定义一个命名空间时#xff0c;可以忽略这个命名空间的名称#xff1a; namespce {char c;int i;double d;}编译器在内部会为这个命名空间生成一个唯一的名字#xff0c;而且还会为这个匿名的命名空间生成一条using指令。所以上面的代码在效果上等同于#xff1a;namespa… 当定义一个命名空间时可以忽略这个命名空间的名称
namespce {char c;int i;double d;}编译器在内部会为这个命名空间生成一个唯一的名字而且还会为这个匿名的命名空间生成一条using指令。所以上面的代码在效果上等同于namespace __UNIQUE_NAME_ {char c;int i;double d;}using namespace __UNIQUE_NAME_; //这样保证该命名空间内的只能被本文将访问因为其他文件没有名字无法引用到在匿名命名空间中声明的名称也将被编译器转换与编译器为这个匿名命名空间生成的唯一内部名称(即这里的__UNIQUE_NAME_)绑定在一起。还有一点很重要就是这些名称具有internal链接属性这和声明为static的全局名称的链接属性是相同的即名称的作用域被限制在当前文件中无法通过在另外的文件中使用extern声明来进行链接。如果不提倡使用全局static声明一个名称拥有internal链接属性则匿名命名空间可以作为一种更好的达到相同效果的方法。注意:命名空间都是具有external 连接属性的,只是匿名的命名空间产生的__UNIQUE_NAME__在别的文件中无法得到,这个唯一的名字是不可见的.C 新的标准中提倡使用匿名命名空间,而不推荐使用static,因为static用在不同的地方,涵义不同,容易造成混淆.另外,static不能修饰class。C 语言的 static 关键字的两种用法 C 语言的 static 关键字有两种用途 1. 用于函数内部修饰变量即函数内的静态变量。这种变量的生存期长于该函数使得函数具有一定的“状态”。使用静态变量的函数一般是不可重入的也不是线程安全的。 2. 用在文件级别函数体之外修饰变量或函数表示该变量或函数只在本文件可见其他文件看不到也访问不到该变量或函数。专业的说法叫“具有 internal linkage”简言之不暴露给别的 translation unit。 C 语言的这两种用法很明确一般也不容易混淆。 C 语言的 static 关键字的四种用法 由于 C 引入了 class在保持与 C 语言兼容的同时static 关键字又有了两种新用法 3. 用于修饰 class 的数据成员即所谓“静态成员”。这种数据成员的生存期大于 class 的对象实体 instance。静态数据成员是每个 class 有一份普通数据成员是每个 instance 有一份因此也分别叫做 class variable 和 instance variable。 4. 用于修饰 class 的成员函数即所谓“静态成员函数”。这种成员函数只能访问 class variable 和其他静态程序函数不能访问 instance variable 或 instance method。 当然这几种用法可以相互组合比如 C 的成员函数无论 static 还是 instance都可以有其局部的静态变量上面的用法 1。对于 class template 和 function template其中的 static 对象的真正个数跟 template instantiation 模板具现化有关相信学过 C 模板的人不会陌生。 可见在 C 里 static 被 overload 了多次。匿名 namespace 的引入是为了减轻 static 的负担它替换了 static 的第 2 种用途。也就是说在 C 里不必使用文件级的 static 关键字我们可以用匿名 namespace 达到相同的效果。其实严格地说linkage 或许稍有不同这里不展开讨论了。 匿名 namespace 的不利之处 在工程实践中匿名 namespace 有两大不利之处 其中的函数难以设断点如果你像我一样使用的是 gdb 这样的文本模式 debugger。使用某些版本的 g 时同一个文件每次编译出来的二进制文件会变化这让某些 build tool 失灵。 另一篇今天得到来自google的老大的指点学习了一个新的用法匿名命名空间。 C另外有一种匿名的命名空间,来保证生成的符号是局部的,这样对于匿名空间中的变量等,外部都是不可见的.//test3.cppstatic void bar(){}namespace //匿名的命名空间
{float bar2;int foo;
}//test4.cpp
extern int foo;
extern void bar();
extern float bar2;
int main()
{
bar(); //外部的bar()被声明为static,这里链接不到符号.不能访问
bar2 0.1f; //外部的匿名空间哩,这里也不能访问.
foo 0xFF;
return 0;
};//如果将test4的目标和test3的目标进行链接,实际上是找不到这些符号的.链接会失败.匿名的命名空间是C的特性,相对于C的static声明来说,可以在匿名的空间里面声明很多变量和函数,这样可以省去了对每个变量和函数添加static声明.
实质上匿名空间的功能跟static声明是一样的. 对于一个大型的C语言软件项目给函数和全局变量起名不是一个容易的事情因为必须考虑有没有可能与其它程序员写的代码冲突多数的做法是对每个模块的一组函数名加个特定前缀如HTRequest_setInternal、HTRequest_internal等。这使得程序员每次调用这些函数时都必须多输出一些字符虽然使用现在比较优秀的IDEIntegrated Development Environment不会给程序员的输入带来多少负责但这些字符看起来还是有些多余。所以C引入了namespace的概念把一些标识符以命名空间树结构的方式组织起来使代码看起来更优雅。而且事实证明该特性是先进的对于大型项目的作用是明显的并且在后来的编程语言如Java、C#、Python都支持此类特性只是有些叫法不同而已。 命名空间不仅可以用于组织类型(class、struct、Enum)等还可以用于组织全局变量、全局函数等。如例程[2-1]所示将不同模块的标识符分别组织到不同的命名空间中从而避免标识符的冲突。 // 例程[2-1] #include iostream namespace sock{ typedef unsigned short socket_port_t; const char* LOOPBACK_ADDR “127.0.0.1”; const socket_port_t DEFUALT_HTTP_PORT 80; } int main( void ) { std::cout”Local HTTP addr “sock::LOOPBACK_ADDR ’:’sock::DEFUALT_HTTP_PORTstd::endl; return 0; } 在大型的C项目中使用命名空间比较好的项目如Google浏览器Chorme、开源C库boost等而没有使用命名空间的一个例子就是开源C库ACEThe ADAPTIVE Communication Environment 它选择了在每个类型的前面加上前缀“ACE_”使得标识符都比较长而且看起来有点儿冗余。为使用起来方便而且不修改ACE的源码可以使用typedef标识符对这些标识符进行重命名如例程[2-2]所示。请注意不能在这里使用#define因为宏不受命名空间的限制。 // 例程[2-2] #include ace/Mutex.h namespace ace{ typedef ACE_Mutex Mutex; typedef ACE_Lock Lock; } 1.1.2. 如何引用命令空间内的标识符 当引用的标识符不在当前命名空间或全局命名空间内时有三种方式可以引用该标识符如引用前一节新定义的ace命令空间中的Mutex类型 // 方式一 ace::Mutex mutex; // 方式二 using ace::Mutex; Mutex mutex; // 方式三 using namespace ace; Mutex mutex; 方式一只在必要的时候通过域运算符“”引用指定命令空间内的标识符适用于当前编译单元引用ace内的标识符不多而且编译单元内使用这些标识符的次数也不多的情况。 方式二只引入ace::Mutex一个标识符如果在当前编译单元内使用ace::Mutex次数较多而且不会与当前命名空间内的标识符冲突建议使用这种方式。 方式三是把ace命名空间中的全部标识符都引入到当前命名空间中此后ace所有的标识符对于当前命名空间都是可见的这会提高标识符冲突的危险。如果当前编译单元用到ace命令空间内的标识符较多而且不会出现标识符冲突的问题可以使用这种方式以减少字符的输入。 对于以上三种方式建议优先选择第一种这种方式最不容易产生标识符冲突方式二次之尽可能不用第三种试即使是对于C标准库也不要使用第三种方式因为至少在Solaris系统中就有一个struct类型叫map ??如果你引用了包含该类型的头文件就会导致命名冲突。 另外建议不要在头文件中使用using语句引入标识符否则这些标识符将被暴露到引用这个头文件的所有编译单元内这样很容易使命名空间失去其作用而产生命名冲突。 对于用到的系统API建议函数名前使用域运算符加以区别使程序可读性更好如::GetLastError( ), ::getcwd( )。 注意切忌在自定义的命名空间中引用系统头文件如例程[2-3]所示避免造成标识符的混乱。 // 例程[2-3] namespace my_space{ #include net/if.h } 1.1.3. 命令空间的别名 当要引用的命名空间比较长而且想用第一种方式引用命名空间内的实体则可以通过命名空间别名为原来的命名空间起个简短的名字如例程[2-4]。 // 例程[2-4] namespace long_namespace{ void func( void ) { /* function body */ } } namespace ns long_namespace; int main( void ) { ns::func(); return 0; } 1.1.4. 匿名命令空间 当声明命名空间时的名称为空时则该命名空间为匿名命名空间(unnamed namespace)。匿名的空间是C用于替代使用static定义作用域为本编译单元的全局函数或全局变量的一种新的替代方式匿名空间与命名的命名空间一样可以嵌套。由于匿名命名空间没有命名空间的名字所以也无法在其它的编译单元内通过extern声明该变量于是该变量自然也只在本编译单元内可见如例程[2-5]。 // 例程[2-5] #include iostream using namespace std; namespace{ int i 256; } namespace ns{ namespace { int i 128; } void func(void) { coutns::func : endl; cout\t::i::iendl; cout\tns::iiendl; } } int main(void ) { cout::iendl; coutiiendl; coutns::ins::iendl; ns::func(); return 0; } 使用匿名空间比使用static至少有两个好处 1) 对于一组多个标识符函数只需要使用一个匿名空间来声明不需要多次输入static。 2) 可以嵌套。这样可以在不同命名空间中使用多个同名的标识符。 在C的标准中也建议使用匿名命名空间间定义编译单元内部的全局变量替代staticstatic关键词在此处被认为是过期的deprecated特性。