为什么 const int 需要 extern,但 const char* 不需要?

6
我对于在我的extern.cpp文件中,使用intchar*的定义时,是否需要extern感到困惑。我有以下测试程序:
// extern.cpp
extern const int my_int = 1;
const char* my_str = "FOO";

// main.cpp
#include <iostream>

extern const int my_int;
extern const char* my_str;

int main() {
  std::cout << my_int;
  std::cout << my_str;
  return 0;
}

如果我从“extern const int my_int = 1;”中删除“extern”,那么我会得到“undefined reference to 'my_int'”。如果我在“const char* my_str = "FOO";”中添加“extern”,则会收到一个警告“'my_str' initialized and declared 'extern'”。为什么我需要在“my_int”上使用“extern”,但是将其添加到“my_str”会生成警告?
这是在gcc 10.1.0上运行的C++17。具体命令如下:
/usr/bin/g++-10  -g -std=gnu++17 -o main.cpp.o -c main.cpp
/usr/bin/g++-10  -g -std=gnu++17 -o extern.cpp.o -c extern.cpp
/usr/bin/g++-10  -g main.cpp.o extern.cpp.o -o TestExtern

4
my_str 不是 const - user253751
3
这回答解决了你的问题吗?C++中何时使用extern - user13088490
1
我错了,实际上@Trovor解释了为什么“const”与“extern”存在问题。 - Slava
extern 永远不应与初始化一起使用。在头文件中使用 extern,然后在某个 ccpp 文件中定义实际变量,而不使用 extern。来自头文件的 extern 声明可以在作用域内,并且其类型必须匹配。 - Zan Lynx
所以,如果你将 my_str 改为 const char * const my_str,那么你仍然会遇到同样的问题。 - Slava
显示剩余3条评论
1个回答

12
这是由于my_intmy_str变量的不同链接引起的。 my_int是命名空间作用域中的一个const限定变量,这意味着它默认具有内部链接。换句话说,在当前的翻译单元中,其可见性是有限的,除非你将其标记为extern。此外,内部链接常量必须有一个初始化程序。
另一方面,my_str没有被const修饰。不要被指针类型中的const限定符所困扰,因为该限定符是指向类型的组成部分。指针本身是可以改变的,并且你可以在运行时给它赋一个不同的值。由于这是一个命名空间作用域中的非const变量,因此它具有外部链接,因此它引用了整个程序范围内的单个指针对象。

1
你的内部链接有点问题。常量不一定是内部的。你可以声明一个 extern const int,但不要尝试将其设置为任何值。这将创建一个链接器引用到 const int 的实际定义。除非使用 LTO,否则它将无法将 const int 内联到代码中,但它将能够通过其内存位置引用它。 - Zan Lynx
1
这是写char const *的一个很好的理由。它是相同的类型,但更清晰地表明了指向的值是常量。在我的看法中,语法const X永远不应该被使用。const总是放在它所适用的类型的部分右侧;出于历史原因,它在某些情况下允许在左侧,但这会造成混淆。在这种情况下,示例类型将是int constchar const *,现在我们可以更清楚地看到指针值不是常量,因为const不是类型中的最后一个标记。 - cdhowie
2
@cdho 西部常量最差常量东部常量最佳常量 - Yakk - Adam Nevraumont
1
@cdhowie 很不幸,C++中已经有太多从C语言继承下来的坏习惯了。常量用大写字母表示,const通常被放错位置,*与变量绑定而非类型等等。 - Slava
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接