正确使用"extern"关键字
Using the 'extern' keyword properly
有一些来源(书籍,在线材料)解释extern
的用法如下:
extern int i; // declaration - has 'extern'
int i = 1; // definition - specified by the absence of 'extern'
并且有一些来源支持以下语法:
extern int i; // declaration
extern int i = 1; // definition - specified by the equal sign
// Both marked with 'extern'
我的问题是 - 这是 C 与 C++ 的区别,还是 ANSI 与 ANSI 之前的实践?
现在,更实际的问题:
使用第二种语法,我想创建一个全局对象(从每个编译单元中可见)。构造函数不带参数,因此括号和等号都不是必需的。
extern MyClass myobject;
现在编译器如何区分声明和定义?
编辑:回到学校,我已经习惯了第一种语法(Borland C)。后来我使用了一个编译器(可能是GCC的某个古老版本),它拒绝编译没有"extern"的定义。这就是让我感到困惑的原因。
具体到您的示例,C 和 C++ 在这里没有区别。在两种语言中都有效的基本规则是:如果您的声明包含初始值设定项,那么它是一个定义。时期。不管它是否有明确的extern
。如果它有一个初始值设定项,那么它是一个定义。
这意味着在命名空间范围内,extern int i = 1
和int i = 1
都是等效的,即 这种声明中的extern
是多余的。在C++ extern
中,当声明的对象被const
时,定义变得非冗余,因为C++中的const
对象默认具有内部链接。例如,extern const int c = 42;
定义了具有外部链接的常量c
。
如果声明没有初始值设定项,则(并且只有这样)它才开始依赖于extern
关键字的存在。对于extern
,它是一个非定义声明。没有extern
它是一个定义。(在 C 中,这将是一个暂定定义,但这在我们的上下文中无关紧要)。
现在,对于您的实际问题。为了创建一个全局对象,您必须将其声明为
extern MyClass myobject;
(通常在头文件中完成),然后在某个翻译单元中将其定义为
MyClass myobject;
由于构造函数不带参数,因此这是定义对象的唯一方法。(从 C++11 开始,如果您愿意,您也可以使用 MyClass myobject{};
。
如果您必须向构造函数提供参数(例如,42
),您将能够同时使用两者
MyClass myobject(42);
和
extern MyClass myobject(42);
作为定义,因为初始值设定项的存在确保它确实被解释为定义。
对于文件范围的变量,无论它们是类类型还是基元类型:
- 没有初始化器的
extern T t;
是一个声明; -
extern T t = expression;
任何语法(赋值、构造或统一)的初始化器都是一个定义; - 没有初始化器的
T t;
是一个定义,初始化为默认值T
; -
T t = expression;
使用任何语法的初始化器作为定义。
extern int i = 1;
和 int i = 1;
之间没有区别,并且两种样式都有争论,但总的来说,我会主张第二种,因为您应该已经知道文件范围内的定义具有链接。
从历史上看,在ANSI C之前,extern
关键字似乎不是必需的;例如参见 http://www.jetcafe.org/jim/c-style.html#Declarations
因此,对于类类型,请为声明编写extern MyClass myobject;
,为定义编写MyClass myobject;
。
草案 n3337, 3.1.2
声明是一个定义,除非它声明了一个没有 指定函数的主体 (8.4),它包含 extern 说明符 (7.1.1) 或链接规范25 (7.5),但都不是初始值设定项 也不是函数体,它在类中声明静态数据成员 定义(9.2,9.4),它是一个类名声明(9.1),它是一个 不透明枚举声明(7.2),它是一个模板参数(14.1),它 是函数声明符中的参数声明 (8.3.5),它是 不是函数定义的声明符,或者它是一个 typedef 声明 (7.1.3)、别名声明 (7.1.3)、使用声明 (7.3.3)、static_assert声明(第7条)、 属性声明(条款 7)、空声明(条款 7)或 使用指令 (7.3.4)。[ 示例:除以下一项外,其他所有项均为 定义:
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // declares static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
whereas these are just declarations:
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares d
—结束示例 ]
我想创建一个全局对象(从每个编译单元中可见)
extern
对于定义不是必需的,因为外部链接是默认设置。
你应该做的是把:
extern MyClass myobject;
在头文件(这不是定义)中,以使编译器在编译其他编译单元时知道数据类型。 然后,在一个编译单元中,写入:
MyClass myobject;
这是一个具有外部联系的定义。
好的,所以 extern
关键字放在外部文件中变量名称之前。假设您的项目中有一个单独的文件。假设该文件是一个名为MyMath.h的头文件(就好像您正在制作带有一些有用函数/类的便携式数学文件一样)。在你的头文件中,你会把所有的原型,或前向引用,用于你的酷数学函数和类。此数学头文件的实际代码或函数等将位于名为 MyMath 的.cpp文件中.cpp(通常您使用相同的名称来保持其组织)。extern
关键字在这里发挥作用:如果你想在你的数学文件中有一个 PI (3.1415) 的全局变量,你需要像往常一样定义它(在.cpp文件中),float PI = 3.1415;
然后在你的 .h 或头文件中编写原型或变量的声明, 前缀为 extern
.
所以完整的示例可能如下所示:
----我的数学.h----
#ifndef MYMATH_H_INCLUDED
#define MYMATH_H_INCLUDED
extern float PI;
#endif // MYMATH_H_INCLUDED
----我的数学.cpp----
#include "MyMath.h"
float PI = 3.1415;
----主要.cpp----
#include <iostream>
#include "MyMath.h"
using namespace std;
int main()
{
cout << "PI = " << PI << endl;
return 0;
}
希望我解释得彻底!请记住,这是为了在文件之间使用变量!
initializer"胜过"extern"。行动胜过空谈。
- 如果全局变量默认是外部变量,为什么要添加"extern"关键字?
- C++17 'inline variable' vs 'extern' 关键字继承自 C 的新功能
- 对 C++ 中的特定标头使用 extern C 关键字是否允许从 void* 转换为 char*?
- extern 关键字在包含文件头文件C++
- 为什么我应该使用extern关键字来声明命名空间范围中的变量
- "extern"关键字用法
- 具有多个文件的extern关键字
- 正确使用"extern"关键字
- CppUTest中extern关键字的替代方案是什么
- 为什么C++编译器允许 extern 关键字与定义相结合
- C++ extern 关键字和全局变量
- 如何使用模板 extern 关键字分隔测试类型
- extern关键字在C++中的用法
- c++ -对extern关键字感到困惑
- 这里需要extern关键字,cpp文件中的const
- extern关键字和多个翻译单元的用法
- 在定义和声明中都指定extern关键字可以吗?
- C++:我无法理解"extern"关键字在我的程序中是如何工作的
- c中的Extern关键字问题
- Extern关键字定义静态数据成员和成员函数,c++