看过不少C++的书籍里都没有明确地指出处声明(declaration)与定义(define)的区别,或者只是提到了需要支持分离式编译,使用extern
specifier的就是声明,不带的就是定义。实际上我觉得C++标准中对于声明(declaration)与定义(define)的区别描述的更为清晰。
《C++ Primer 5th》中2.2.2
节提到变量声明与定义的关系:
为了支持分离式编译,C++语言将声明和定义区分开来。声明(declaration)**使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含那个名字的声明。而定义(define)**负责创建与名字相关联的实体。
如果想要声明一个变量而非定义它,就在变量名前面添加关键字extern
,而且不要显式地初始化变量。
1 | extern int i; // 声明i而非定义i |
任何包含了显式初始化的声明即成为定义。我们能给extern关键字标记的变量一个初始值,但这么做就抵消了extern的作用。extern语句如果包含初始值就不再是声明,而变成定义了。
1 | extern double pi=3.14159; // 定义 |
以上是C++ Primer中对于变量声明和定义的关系的描述。
我觉得C++标准的描述更全面一些:
A declaration is a definition unless:
- it declares a function without specifying the function’s body (8.4),
- it contains the extern specifier (7.1.1) or a linkage-specification (7.5) and neither an initializer nor a function- body,
- it declares a static data member in a class definition (9.2, 9.4),
- it is a class name declaration (9.1),
- it is an opaque-enum-declaration (7.2),
- it is a template-parameter (14.1),
- it is a parameter-declaration (8.3.5) in a function declarator that is not the declarator of a function-definition,or
- it is a typedef declaration (7.1.3),
- an alias-declaration (7.1.3),
- a using-declaration (7.3.3),
- a static_assert-declaration (Clause 7),
- an attribute- declaration (Clause 7),
- an empty-declaration (Clause 7), or
- a using-directive (7.3.4).
我来简单翻译一下。
一个声明是一个定义,除非
- 声明一个函数但没有指定函数体
1 | int func(); // 声明 |
- 包含一个extern说明符或一个linkage-specification(e.g:extern “C”)且既没有一个初始化器也没有一个函数体。
1 | extern int x; |
- 在类定义的内部声明一个static数据成员。
1 | struct A{ |
- 一个类名字声明。
1 | struct A; |
- 一个opaque-enum-declaration(没想好这个要咋翻译)
1 | enum A:int; |
- 一个模板形参(template parameter)
1 | template<typename T> T f(T); //T is a decleration |
- 函数声明中的形参声明
1 | int func(int x); |
- 一个typedef声明
1 | typedef int INT; |
- 一个别名(alias)声明
1 | using INT=int; |
- 一个using声明
1 | namespace A{ |
- 一个static_assert声明
1 | static_assert(foo()); |
- 一个属性声明
1 | [[noreturn]] void funv(); |
- 一个空的声明
1 | // empty-declaration: |
- 一个using指令
1 | using namespace std; |
在以上的十几种情况中,声明不是定义。简单地说,“声明”就是提供名字和参数等一些原型信息,而“定义”则是提供存储空间分配和相应的实现。
额,写完才发现cppreference上已经有:Define and ODR,郁闷…