首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C/C++较少见的关键字- register、volatile、extern、explicit

C/C++较少见的关键字- register、volatile、extern、explicit
EN

Stack Overflow用户
提问于 2011-07-28 07:37:45
回答 5查看 7.9K关注 0票数 15

你能给我快速浏览一下这4个关键字的用途和原因吗?

我理解谷歌会告诉你的关于注册和易失性的基础知识,但我想知道更多(只是一个实用的概述)。Extern和explicit让我有点困惑,因为我从来没有找到自己必须使用它们的理由,尽管我做的是相当低级的嵌入式系统代码。再说一次,我可以在谷歌上搜索,但我更喜欢专家的快速、实用的总结,这样它就会留在我的脑海里。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-07-28 07:56:19

外部

extern被重载用于多个用途。对于全局变量,这意味着它正在声明变量,而不是定义它。这对于将全局变量放入头部非常有用。如果您将其放在标题中:

代码语言:javascript
复制
int someInteger;

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

代码语言:javascript
复制
extern int someInteger;

现在,在一个.cpp文件中,您可以定义int someInteger,这样它就只有一个副本。

还有extern "C",它用于指定某些函数使用C链接规则而不是C++。这对于与C编译的库和代码的接口很有用。

在C++0x中,也会有extern template声明。这些是显式模板实例化的对立面。执行此操作时:

代码语言:javascript
复制
template class std::vector<int>;

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

代码语言:javascript
复制
extern template class std::vector<int>;

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

显式

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

代码语言:javascript
复制
ClassName(int someInteger);

这意味着,如果您有一个接受ClassName的函数,用户可以使用int调用它,转换将自动完成。

代码语言:javascript
复制
void SomeFunc(const ClassName &className);
SomeFunc(3);

这是合法的,因为ClassName有一个接受整数的转换构造函数。这就是接受std::string的函数也可以接受char*的原因;std::string有一个接受char*的构造函数。

然而,大多数时候你并不想要像这样的隐式转换。您通常只希望转换是显式的。是的,它有时和std::string一样有用,但对于不合适的转换,您需要一种方法来关闭它。输入explicit

代码语言:javascript
复制
explicit ClassName(int someInteger);

这将阻止隐式转换。您仍然可以使用SomeFunc(ClassName(3));,但SomeFunc(3)将不再有效。

顺便说一句:如果explicit对你来说很少见,那么你对它的使用还远远不够。你应该一直使用它,除非你特别想要转换。这种情况并不常见。

易失性

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

有时候,你会想要停止这一切。在这些情况下,您可以使用volatile;这会阻止这些优化。

寄存器

这只是一个提示。它告诉编译器尝试将变量的数据放入寄存器中。这在本质上是不必要的;编译器比你更擅长决定什么应该是一个寄存器,什么不应该是一个寄存器。

票数 28
EN

Stack Overflow用户

发布于 2011-07-28 07:46:34

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

volatile表示内存可能会在程序实际执行任何操作的情况下发生更改。这是对编译器的另一个提示,它应该避免优化对该位置的访问。例如,如果您对同一位置连续写入了两次,并且没有中间读取,则编译器可能会优化掉第一次写入。但是,如果您要写入的位置是一个硬件寄存器,则需要完全按照写入的方式执行每次写入。所以volatile就像在说“在这件事上相信我”。

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

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

票数 7
EN

Stack Overflow用户

发布于 2011-07-28 07:45:46

register现在大多被忽略了,但它应该是在暗示编译器,你更希望变量在寄存器中,而不是堆栈中。优化器现在做得很好,现在已经无关紧要了。

volatile告诉编译器不要假设值只从当前线程更改,因此它将始终读取实际内存值,而不是在两次读取之间缓存它。它对多线程应用程序很有用,但无论如何你最好使用操作系统原语(事件、信号量等)。

extern并没有定义这个值,它只是声明了它。它主要用于从动态链接库或共享库(.a)中导出和导入函数。副作用还允许您使用extern "C"关闭C++的名称损坏。

explicit允许您指定构造函数必须是显式的,而不是隐式转换构造函数(在隐式转换构造函数中,如果具有接受int的隐式构造函数,则可以编写CMyClass val=10; )。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6852522

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档