C ++中变量的声明和定义有啥区别? [复制]

Posted

技术标签:

【中文标题】C ++中变量的声明和定义有啥区别? [复制]【英文标题】:What is the difference between declaration and definition of a variable in C++? [duplicate]C ++中变量的声明和定义有什么区别? [复制] 【发布时间】:2015-07-09 08:33:02 【问题描述】:

我的问题源于对 Scott Meyers 的 Effective C++ 的研究。 在那本书的第二条中,写了以下内容:

要将常量的范围限制为类,您必须将其设为成员,并且为了确保最多有一个常量副本,您必须将其设为静态成员。

写的很对。然后立即给出以下示例:

class GamePlayer 
private:
    static const int NumTurns = 5;
    int scores[NumTurns];
    ....
  ;

那么下面就是上面例子的写法:

您在上面看到的是声明,而不是 NumTurns 的定义。

我的第一个问题是:这句话是什么意思?

紧接着提到以下内容:

通常 C++ 要求您为使用的任何内容提供定义,但静态和整数类型(例如 - 整数、字符、布尔值)的类特定常量是一个例外。只要你不取他们的地址,你可以在不提供定义的情况下声明和使用它们。如果您确实获取了类常量的地址,或者即使您不获取地址,编译器也错误地坚持定义,您可以提供一个单独的定义,如下所示: const int GamePlayer::Numturns; //definition of NumTurns

为什么现在是定义而不是声明?

我理解函数上下文中的差异,但不理解常规变量上下文中的差异。另外,有人可以通过

来扩展作者的意思吗

... 如果您确实获取了类常量的地址,或者如果您的 .. 上面引用的段落的一部分?

P.S : 我是 C++ 的新手。

【问题讨论】:

这本书肯定解释了这一点......另外,快速谷歌搜索带来了这篇解释得很好的文章:cprogramming.com/declare_vs_define.html @Amxx 是的,好点。这也是一个格式非常好的问题。 +1。 这与odr rules 相关,如果一个变量没有被 odr 使用,那么它就不需要类外定义。 ***.com/questions/1410563/… 我喜欢将在类中初始化的静态数据成员称为“带有初始化程序的声明”。它们从来都不是定义。 【参考方案1】:

声明here:

在类接口中初始化的静态const 整数数据成员不是可寻址变量。它们只是其关联值的符号名称。由于它们不是变量,因此无法确定它们的地址。请注意,这不是编译问题,而是链接问题。在类接口中初始化的静态const 变量不作为可寻址实体存在。

这里的“可寻址实体”指的是静态const数据类型的“实例”。没有实例,没有地址,即它只是一个声明。 请注意,在源文件中明确定义的静态变量可以正确链接。

class X

    public:
        static int const s_x = 34;
        static int const s_y;
;

int const X::s_y = 12;

int main()

    int const *ip = &X::s_x;    // compiles, but fails to link
    ip = &X::s_y;               // compiles and links correctly
 

...如果您确实采用了类常量的地址,或者您的 .. 上面引用的段落的一部分?

means 如果这样的成员被 odr-used,则仍然需要命名空间范围内的定义,但它不应该有初始化程序。

struct X 
    const static int n = 1;
;
const int* p = &X::n; // X::n is odr-used
const int X::n;       // ... so a definition is necessary

【讨论】:

那句话不正确。您可以定义一个 const 整数数据成员并获取其地址。 @Columbo;它的static const 抱歉,我删除了静电。评论仍然有效。 coliru.stacked-crooked.com/a/1b633f6939183e52 @Columbo;我好奇。你有任何来自标准的报价吗? @Columbo - 不,你不能。你不应该对这个答案投反对票(我假设你是投反对票的人。)coliru.stacked-crooked.com/a/9c5df94daf8a700e【参考方案2】:

就像函数一样,变量可以有“纯声明性”声明和实际定义。你很困惑,因为你之前可能没有遇到过很多纯变量声明。

int i; // Definition
extern int i, j; // (Re)declares i, and declares j
extern int j = 0; // Defines j (confusing, eh?)

正如您习惯使用函数一样,定义就是声明,但并非所有声明都是定义。 §3.1/2 阅读

声明是一个定义,除非 […] 它声明一个静态数据 类定义中的成员(9.2、9.4),

因此,类内静态数据成员声明永远不会定义它们声明的变量。但是,有时不必存在变量定义。 当您可以直接使用它的值而不需要变量运行时存在时就是这种情况。

在技术术语中,只要静态数据成员(或任何实体,就此而言)不是“使用过的”,就不必定义它。 §3.2/3 中定义了所有实体的Odr 使用

变量x,其名称显示为潜在评估表达式 exexodr-used 除非应用左值到右值的转换 (4.1) 到 x 产生一个不调用的常量表达式 (5.20) 任何重要的函数,如果x 是一个对象,ex 是一个元素 表达式e 的一组潜在结果,其中 左值到右值转换 (4.1) 应用于 e,或者 e 是 丢弃值表达式(第 5 条)。

这看起来很复杂,在标准的早期版本中它更简单。但是,它粗略地说,当某个表达式“立即”访问变量值时,该变量不会被某个表达式使用,并且这种访问会产生一个常量表达式。 Meyers 的“获取地址”示例只是众多用于 odr 的示例之一。

对于某个类A及其静态数据成员i

class A 
    static const int i = 57; // Declaration, not definition
;

const int A::i; // Definition in namespace scope. Not required per se.

【讨论】:

【参考方案3】:

为什么现在是定义而不是声明?

因为这个语句会导致编译器为静态变量生成一个地址。

另外,有人可以通过“如果你采取 类常量的地址”:

当你让一个指针指向一个变量时,你会获取它的地址。

【讨论】:

【参考方案4】:

简短的回答是:声明说“这东西存在于某处”,而定义导致分配空间。在您的情况下,您已将其声明为静态和常量。编译器可能足够聪明地注意到,如果您只将它用作值,它可以简单地用文字 5 替换该用法。它实际上不需要在某处为变量腾出空间并用 5 填充它,它可以在编译时直接使用 5。但是,如果您获取它的地址,编译器将无法再做出该假设,现在需要将该 5 放入可寻址的某个位置。编译器需要它存在于一个翻译单元中(大致:一个 cpp 文件。另请参见一个定义规则。),所以现在你必须在某处显式声明它。

【讨论】:

以上是关于C ++中变量的声明和定义有啥区别? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

c语言中函数定义和声明有啥区别

在C语言中声明和定义的区别?

C语言变量的定义和声明有啥不同?

请问C++中啥是函数的定义性声明和函数的引用性声明,有啥区别

C语言结构体中struct和typedef struct有啥区别?

下面示例中的声明和定义有啥区别? [复制]