混合extern和const

时间:2010-02-03 09:32:14

标签: c++ c const scope extern

我可以将extern和const混合为 extern const 吗?如果是,那么 const 限定符是否仅在其声明的范围内强加它,或者它是否与它声明的转换单元的声明完全匹配?即即使实际的 i 不是const,我也可以声明extern const int i;,反之亦然吗?

5 个答案:

答案 0 :(得分:47)

  • 是的,你可以一起使用它们。
  • 是的,它应该与它实际声明的翻译单元中的声明完全匹配。除非您当然参与Underhanded C Programming Contest: - )

通常的模式是:

  • file.h:
    extern const int a_global_var;
  • file.c:
    #include "file.h"
    const int a_global_var = /* some const expression */;

编辑:合并legends2k的评论。感谢。

答案 1 :(得分:5)

您可以一起使用它们。但是你需要在使用const时保持一致,因为当C ++命名装饰时,const包含在用于装饰符号名称的类型信息中。因此extern const int i将引用与extern int i

不同的变量

除非你使用extern“C”{}。 C名称装饰不注意const。

答案 2 :(得分:1)

你可以一起使用它们,你可以做各种忽略const关键字的事情,因为就是这样;一个关键字。它告诉编译器你不会改变一个变量,这反过来又允许编译器做一些有用的opomisations并阻止你改变你不想要的东西。

Possibility.com a decent article有更多背景资料。

答案 3 :(得分:1)

C ++ 17 inline变量

如果您认为自己想使用extern const,那么您实际上更可能想使用C++17 inline variables

这项令人敬畏的C ++ 17功能使我们能够:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline constexpr int notmain_i = 42;

const int* notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

const int* notmain_func() {
    return &notmain_i;
}

编译并运行:

g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main

GitHub upstream

另请参阅:How do inline variables work?

内联变量的C ++标准

C ++标准保证地址相同。 C++17 N4659 standard draft 10.1.6“内联说明符”:

  

6具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址。

cppreference https://en.cppreference.com/w/cpp/language/inline解释说,如果未提供static,则它具有外部链接。

内联变量实现

我们可以观察到它是如何实现的:

nm main.o notmain.o

其中包含:

main.o:
                 U _GLOBAL_OFFSET_TABLE_
                 U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
                 U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i

notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i

man nm说说u

  

“ u”该符号是唯一的全局符号。这是对ELF符号绑定的标准集合的GNU扩展。对于这样的符号,动态链接器将确保在整个过程中                  只有一个使用此名称和类型的符号。

所以我们看到有一个专用的ELF扩展。

C ++之前的17:extern const

extern const确实可以按照以下示例工作,但是inline的缺点是:

  • 使用这种技术无法创建变量constexpr,只有inline允许:How to declare constexpr extern?
  • 它不太优雅,因为您必须在头文件和cpp文件中分别声明和定义变量

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.cpp

#include "notmain.hpp"

const int notmain_i = 42;

const int* notmain_func() {
    return &notmain_i;
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

extern const int notmain_i;

const int* notmain_func();

#endif

GitHub upstream

可以完全内联吗?

TODO:有什么方法可以完全内联变量,而无需使用任何内存?

非常类似于预处理器。

这需要某种方式:

  • 禁止或检测变量地址是否被占用
  • 将该信息添加到ELF对象文件中,然后让LTO对其进行优化

相关:

在Ubuntu 18.10,GCC 8.2.0中进行了测试。

答案 4 :(得分:-1)

是的,你可以一起使用它们。

如果你声明“extern const int i”,那么我就是整个范围的const。不可能将它重新定义为非常量。当然你可以通过抛弃它来绕过const标志(使用const_cast)。