`

匿名namespace的作用以及它与static的区别

    博客分类:
  • c++
阅读更多

一。匿名namespace的作用

在C语言中,如果我们在多个tu(translation unit)中使用了同一个名字做

为函数名或者全局变量名,则在链接阶段就会发生重定义错误,为了解决这个

问题,我们可以在定义这些标识符 (identifier)的时候加上static关键字修

饰以限制它只在一个tu范围内可见。

C++继承了C语言中static关键字的 这个用途,我们依旧可以使用static来避免

多个tu中使用同一个标识符带来的重定义问题。此外C++还提供了另一种特有

的方式,那就 是匿名namespace:一个没有指定名字的namespace被称为一个匿

名namespace;在一个tu中可以出现多个匿名 namespace,并且相同层次的匿名

namespace实际上被合成为同一个;出现在不同tu的匿名namespace中的相同标

识 符相互独立不会发生冲突,因此我们可以把那些只希望在同一个tu范围可见

的全局标识符放入一个匿名namespace中,效果与前面加 static相同。

 

二。匿名namespace与static的区别

一个全局标识符被static修饰后它的linkage变为 internal linkage,这就是

为什么不同tu中的相同标识符不会发生冲突的原因。

而匿名namespace却并不会改变在它 内部定义的标识符的linkage,它用来避免

名字冲突所采用的手段同C++用来实现重载的手段一摸一样,就是使用名字改

编(name mangling):根据C++标准7.3.1.1,每个tu中的匿名namespace实际

上会拥有一个独一无二的名字,因此在不同tu的匿名 namespace中相同的标识

符实际上属于不同的namespace,自然在名字改编后就不会发生冲突了:

[quote

7.3.1.1 Unnamed namespaces [namespace.unnamed]

An unnamed-namespace-definition behaves as if it were replaced by

        namespace unique { }

        using namespace unique;

        namespace unique { namespace-body }

where all occurrences of unique in a translation unit are replaced

by the same identifier and this identifier differs from all other

identifiers in the entire program.

end quote]

为什么匿名namespace不采取跟static一样的做法呢,搞个新花 样岂不是增加

了编译器开发的负担?这其实是因为另一个C++的特性牵制了匿名namespace的

实现,那就是模板非类型参数 (template non-type arguments):

[quote

14.3.2 Template non-type arguments [temp.arg.nontype]

A template-argument for a non-type, non-template template-parameter

shall be one of:

— an integral constant-expression of integral or enumeration type; or

— the name of a non-type template-parameter; or

— the address of an object or function with external linkage, including

   function templates and function template-ids but excluding non-static

   class members, expressed as & id-expression where the & is optional

   if the name refers to a function or array, or if the corresponding

   template-parameter is a reference; or

— a pointer to member expressed as described in 5.3.1 .

end quote]

正是被红字标出的external linkage这一需求限制了匿名namespace的实现!

试想一下,假如我们有一个全局对象或者函数只希望它在一个tu中有效,又

希 望能够用它的地址来实例化一个模板,怎么办?只在一个tu中有效,可以

选择internal linkage,但是要用它的地址做为模板参数,又要求它必须要

是external linkage!!

很显然,匿名namespace 不改变其内部标识符的linkage这一性质解决了这一

难题,我们可以把这个全局对象或者函数放心的扔在一个匿名namespace中,

然 后用它的地址来实例化一个模板,绝对不会发生重定义错误:)

 

现在大部分C++书籍都认为匿名namespace和static是相同的, 而正如这里所阐

述的,它们之间差异是明显的:static修饰的标识符由于internal linkage的

限制,是不能用来实例化模 板的!

 

 

最后给出一个例子证实匿名namespace确实不改变linkage,呵呵

代码中验证了external linkage/internal linkage/no linkage三种情况

---------------------------------------------------------

template <char *p>

struct foo

{

  void bar();

};

 

static char a ='a';

 

namespace

{

  char b = 'b';

  static char c = 'c';

 

  template <class T> struct xxx {};

 

  void foobar()

  {

    struct no_linkage {};

    xxx<no_linkage>();  // 如果编译错误,说明no_linkage的linkage没有变化

  }

}

 

int main()

{

  foo<&a>().bar();  // 由于a的linkage是internal,因此应该编译错误

  foo<&b>().bar();  // 如果编译正确,说明b的linkage是external

  foo<&c>().bar();  // 如果编译错误,说明c的linkage是internal

 

  foobar();

 

  return 0;

}

 

匿名 namespace 的不利之处

在工程实践中,匿名 namespace 有两大不利之处:

其中的函数难以设断点,如果你像我一样使用的是 gdb 这样的文本模式 debugger。

使用某些版本的 g++ 时,同一个文件每次编译出来的二进制文件会变化,这让某些 build tool 失灵。

分享到:
评论

相关推荐

    C++工程实践经验谈

    为了解决这个问题,C++引入了匿名namespace作为一种替代方案,用于替代C语言中文件级`static`的作用,即限制作用域,使变量或函数仅在当前编译单元可见。 **匿名namespace的不利之处** 尽管匿名namespace在很多...

    C++中名称空间namespace的使用方法示例

    同时,C++ 允许创建匿名名称空间,即没有名字的名称空间,它们的作用域仅限于当前文件,类似于 `static` 关键字的效果,但推荐使用匿名名称空间而非 `static`。 在设计库或类库时,将它们放入一个名称空间是一种...

    C++工程实践经验

    匿名namespace是C++中的一种特性,旨在为特定的作用域内的标识符提供唯一性,避免命名冲突。通常在单个源文件中,为了实现局部变量或者函数的全局可见性但又希望限制其作用范围时,会使用匿名namespace。 **详细...

    c语言中的#的作用.pdf

    宏还可以用来创建匿名变量,如文档中的ANONYMOUS(static int)宏定义,它会创建一个静态整型变量,并带有自动递增的行号作为变量名,例如: ```c ANONYMOUS(static int); // 这会被展开为 static int _anonymousXX; `...

    C++复习专用比较,超硬核

    - 匿名命名空间通常用于避免污染全局作用域,用 `static` 修饰的变量只在其作用域内可见。 4. **using声明与using编译指令**: - `using` 声明如 `using LOL::sunwukongID` 可使别名在当前作用域可见,但可能导致...

    国外网站上找到的C++经典问题_c++基础

    - 匿名命名空间中的内容仅在其所在编译单元(`.cpp`文件)内可见,类似于C中的`static`关键字。 3. **命名空间的作用域**: - 在其他编译单元中使用命名空间内的内容需要明确指定命名空间的前缀。 - 可以使用`...

    PHP 函数的操作

    闭包可以访问自身范围内的变量,以及包含它的函数或类的作用域中的变量。 6. **变量作用域**: PHP有四个内置的作用域:`global`、`local`、`static`和`parameter`。`global`作用域允许你在函数外部定义的变量在...

    PHP开发实战宝典第5章源码

    5. **匿名函数与闭包**: - PHP 5.3 引入了匿名函数,它是一个没有名字的函数,常用于简短的、一次性使用的代码块。闭包是匿名函数的一个特殊形式,它可以访问并修改外部函数的变量。 - 使用`use`关键字捕获外部...

    .NET技术学习大纲

    学习`namespace`的使用,掌握类型转换、`is`与`as`的操作,熟悉抽象类和接口的区别与联系。同时,了解遍历集合时`foreach`循环的用法,以及如何生成随机数。 - **常用类库**:掌握`String`与`StringBuilder`的使用...

    PHP方法代码

    PHP 5.3 引入了匿名函数,它是一个没有名字的函数,通常用于回调或者简单的任务: ```php $closure = function($arg1, $arg2) { return $arg1 + $arg2; }; echo $closure(3, 5); // 输出 8 ``` 5. **魔术...

    php 5.3.29 vc9 x86 带libmysql.dll

    2. **晚期静态绑定(Late Static Bindings)**:解决在继承链中静态方法调用的上下文问题,使得静态方法调用能指向实际调用它的类。 3. **闭包(Closures)**:也称为匿名函数,可以作为值传递,增强了函数式编程的能力...

    C++相关高频经典面试题100问.pdf

    引用与指针的区别 - **引用**:本质上是别名,不拥有自己的内存空间;初始化后不能重新绑定。 - **指针**:指向内存地址,可以重新指向不同的地址;需要显式解引用才能访问所指内容。 #### 4. 函数重载 - **定义**...

    C#匿名委托和Java匿名局部内部类使用方法示例

    测试代码 代码如下:using System;using System.Collections.Generic;...namespace CSharpStudy{ class Program { static void Main(string[] args) { int i = 0;  Action action1 = () =&gt; { 

    C++命名空间5种常见用法实例解析

    通过以上五种用法,我们可以看到C++命名空间在解决代码冲突、模块化、管理全局变量、枚举命名以及封装实现等方面都有重要作用。在实际编程中,合理使用命名空间能极大地提高代码的可读性、可维护性和整体质量。对于...

    PHP5.3入门经典(Beginning PHP 5.3)源码+中文PDF+英文PDF

    3. **闭包(Closure)**:闭包是PHP5.3引入的另一大亮点,它是一种匿名函数,可以捕获其所在作用域的变量,这在处理回调函数、异步编程或延迟执行等场景中非常有用。 4. **改进的错误处理**:PHP5.3支持异常处理,...

    PHP的十个高级技巧(TXT)

    1. **闭包与匿名函数**: PHP 5.3 引入了闭包,这是一种可以捕获其所在作用域变量的匿名函数。闭包可以作为参数传递,也可以作为返回值。使用`use`关键字可以引用外部变量,增强了代码的灵活性。 2. **魔术方法**: ...

    PHP之基础语法函数

    静态关键字 `static` 用于定义静态方法和属性。静态属性和方法可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问。 ### 接口 接口(interface)中也可以定义常量。更多示例见文档中的接口...

    javascript 类和命名空间的模拟代码

    通过这样的方式,我们可以将相关的函数和变量组织在NameSpace对象下,减少全局作用域中的变量冲突。 接下来,我们讨论如何模拟类。在JavaScript中,类的模拟通常通过构造函数(constructor)和原型链(prototype)...

    php-5.3.10-Win32-VC9

    1. 函数命名空间:支持使用namespace来组织代码,减少了全局作用域的污染。 2. Late Static Bindings:允许静态方法调用时绑定到实际调用类,增强了面向对象编程的能力。 3. Closure(匿名函数):提供了闭包功能,...

Global site tag (gtag.js) - Google Analytics