C/C++ Rarer关键字 - register,volatile,extern,explicit

Joh*_*0te 14 c c++

您能否快速了解这4个关键字的用途以及原因?

我理解谷歌会在注册和易失性方面告诉你的基础知识,但想了解更多(仅仅是一个实用的概述).虽然做了相当低级的嵌入式系统代码,但是我从来没有找到过自己使用它们的理由,因此外部和明确地让我感到困惑.同样,我可以google但我更喜欢专家的快速,实用的总结,所以它坚持我的想法.

Nic*_*las 27

EXTERN

extern超载用于多种用途.对于全局变量,它意味着它声明变量,而不是定义变量.这对于将全局变量放在标头中很有用.如果你把它放在标题中:

int someInteger;
Run Code Online (Sandbox Code Playgroud)

包含该标头的每个.cpp文件都会尝试拥有自己的.cpp文件someInteger.这将导致链接器错误.通过声明它extern,你所说的只是someInteger代码中会有一个地方:

extern int someInteger;
Run Code Online (Sandbox Code Playgroud)

现在,在.cpp文件中,您可以定义int someInteger,以便只有一个副本.

还有extern "C",用于指定某些函数使用C链接规则而不是C++.这对于与编译为C的库和代码进行交互很有用.

在C++ 0x中,也会有extern template声明.这些与显式模板实例化相反.当你这样做:

template class std::vector<int>;
Run Code Online (Sandbox Code Playgroud)

你告诉编译器现在就实例化这个模板.通常,实例化会延迟到第一次使用模板为止.在C++ 0x中,您可以说:

extern template class std::vector<int>;
Run Code Online (Sandbox Code Playgroud)

这告诉编译器实例化这个模板,在这个.cpp文件,永远.这样,您就可以控制实例化模板的位置.明智地使用它可以大大改善编译时间.

明确的

这用于防止类型的自动转换.如果您有一个ClassName具有以下构造函数的类:

ClassName(int someInteger);
Run Code Online (Sandbox Code Playgroud)

这意味着如果你有一个带a的函数,ClassName用户可以用a 调用它,int转换将自动完成.

void SomeFunc(const ClassName &className);
SomeFunc(3);
Run Code Online (Sandbox Code Playgroud)

这是合法的,因为它ClassName有一个带整数的转换构造函数.这就是采取的功能也std::string可以采取的char*; std::string有一个构造函数,需要一个char*.

但是,大多数情况下,您不希望像这样进行隐式转换.您通常只希望转换是明确的.是的,它有时像std :: string一样有用,但你需要一种方法来关闭不合适的转换.输入explicit:

explicit ClassName(int someInteger);
Run Code Online (Sandbox Code Playgroud)

这样可以防止隐式转换.您仍然可以使用SomeFunc(ClassName(3));SomeFunc(3)不再有效.

顺便说一句:如果explicit对你来说很少见,那么你就不会使用它了.您应该始终使用它,除非您特别想要转换.这不常见.

挥发物

这可以防止某些有用的优化.通常情况下,如果你有一个变量,C/C++会假设它的内容只有在明确改变它们时才会改变.因此,如果将a声明int someInteger;为全局变量,则C/C++编译器可以在本地缓存该值,而不是每次使用时都不经常访问该值.

有时,你想要阻止它.在那些情况下,你使用volatile; 这可以防止这些优化.

寄存器

这只是一个提示.它告诉编译器尝试将变量的数据放入寄存器中.这基本上是不必要的; 编译器比决定什么应该和不应该是一个寄存器更好.

  • +1 - 整体答案很棒.重新"易失","只有在显式改变它们时才改变":即在周围的代码/流中,而不是通过中断处理程序或其他线程.另外,`volatile`还确保*将*写入变量创建机器代码级写入内存(而不仅仅是寄存器) - 这并不一定意味着CPU的核心特定高速缓存将一直刷新该写入物理内存,所以它不是内存屏障或锁的替代品. (3认同)

Jay*_*rod 7

register用作编译器的提示,即变量应存储在寄存器中而不是存储在堆栈中.编译器经常会忽略它并做任何他们想做的事情; 如果可能的话,变量将被分配到寄存器中.

volatile表示在程序实际执行任何操作时内存可能会更改 这是编译器应该避免优化对该位置的访问的另一个提示.例如,如果您有两次连续写入同一位置而没有插入读取,则编译器可能会优化掉第一个.但是,如果您要写入的位置是硬件寄存器,则需要完成所有写入操作,完全按照写入方式进行.所以volatile就像说"只相信我".

extern表示定义发生在当前文件之外.对全局变量有用,但无论如何通常都隐含在声明中.正如Blindy所说,它对于指示一个函数应该具有C链接也很有用.具有C链接的函数将使用其实际名称作为其输出可执行文件中的符号进行编译.C++函数包含更多信息,例如符号中参数的类型.这就是为什么重载在C++中工作但在C中不工作的原因.

explicit适用于C++构造函数.这意味着不应该隐式调用构造函数.例如,假设您有一个Array带有接受整数的构造函数的类capacity.您不希望整数值被隐式转换为Array对象,因为它有一个整数构造函数.