【问题标题】:static and extern global variables in C and C++C 和 C++ 中的静态和外部全局变量
【发布时间】:2012-06-18 19:49:58
【问题描述】:

我制作了 2 个项目,第一个用 C 语言,第二个用 C++ 语言,两者都具有相同的行为。

C 项目:

header.h

int varGlobal=7;

ma​​in.c

#include <stdio.h>
#include <stdlib.h>
#include "header.h"

void function(int i)
{
    static int a=0;
    a++;
    int t=i;
    i=varGlobal;
    varGlobal=t;
    printf("Call #%d:\ni=%d\nvarGlobal=%d\n\n",a,i,varGlobal,t);
}

int main() {
    function(4);
    function(6);
    function(12);
    return 0;
}

C++ 项目:

header.h

int varGlobal=7;

ma​​in.cpp

#include <iostream>
#include "header.h"
using namespace std;

void function(int i)
{
    static int a=0;
    int t=i;
    a++;
    i=varGlobal;
    varGlobal=t;
    cout<<"Call #"<<a<<":"<<endl<<"i="<<i<<endl<<"varGlobal="<<varGlobal<<endl<<endl; 
}

int main() {
    function(4);
    function(6);
    function(12);
    return 0;
}

我读到全局变量在默认情况下是 extern 在 C 中,在 C++ 中默认是 static;那么为什么 C++ 代码可以工作呢?

我的意思是 int varGlobal=7;static int varGlobal=7; 相同,如果它是静态的,那么它只能在声明的文件中使用,对吧?

【问题讨论】:

  • 首先请注意include 只是复制粘贴内容。因此对于这样的单个文件示例,应该将其删除以简化。

标签: c++ c static global-variables extern


【解决方案1】:

在 C 和 C++ 上,全局变量默认不是 extern 也不是 static。 当您将变量声明为static 时,您将其限制为当前源文件。如果您将其声明为extern,则表示该变量存在,但在其他地方定义,如果您没有在其他地方定义它(没有extern 关键字),您将收到链接错误(符号不是找到)。

当您拥有更多包含该标头的源文件时,您的代码将中断,在链接时您将多次引用varGlobal。如果您将其声明为static,那么它将与多个源一起工作(我的意思是,它将编译和链接),但每个源都有自己的varGlobal

您可以在 C++ 中做而在 C 中不能做的事情是在标头上将变量声明为 const,如下所示:

const int varGlobal = 7;

并包含在多个来源中,而不会在链接时破坏事物。这个想法是用常量替换旧的 C 风格 #define

如果您需要在多个源而不是 const 上可见的全局变量,请在标题中将其声明为 extern,然后在源文件中定义它,这次不使用 extern 关键字:

多个文件包含的头文件:

extern int varGlobal;

在您的一个源文件中:

int varGlobal = 7;

【讨论】:

  • 正如我刚刚发现的,C 和 C++ 之间存在 差异,但它仅适用于 const 对象:publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/…
  • 如果你要把东西放在头文件中,一些编译器/链接器会抱怨多重定义的符号。示例:const int varGlobal=7; 因为您将其声明为const,所以可以将其视为全局常量,但有些编译器并不那么聪明。始终有效的方法是在头文件中声明 static const,如下所示:static const int varGlobal = 7; 这样即使编译器很愚蠢,它也不会将符号添加到外部符号表中,链接器也永远不会请参阅多重定义的符号。
  • @fbafelipe 没错。我忘记了它,因为通常有一种方法可以禁用警告并且我总是使用它。例如,使用 GCC,您可以使用 __attribute__ ((unused)) 禁用该警告。所以我实际上并没有声明东西static const,我声明它们LIBCONST,其中LIBCONST是我创建的#define宏,它为GCC声明static __attribute__ ((unused)),而对于其他平台只声明static t 警告。
  • @lmiguelvargasf 如果要使用值进行初始化,请在 c/cpp 文件中进行初始化,而不是在头文件中进行初始化。所以在标题中你有extern int x;,在源文件中你有int x = 10;
  • 从 C++11 开始,您通常使用 constexpr int constGlobal = 7; 替换旧样式 #define constGlobal = 7。它保证是编译时常量(并且可以用作模板参数等),但仍然是类型安全的。
【解决方案2】:

当您#include 标头时,就好像您将代码放入源文件本身一样。在这两种情况下,varGlobal 变量都在源代码中定义,因此无论它如何声明它都可以工作。

正如 cmets 中所指出的,文件范围内的 C++ 变量在范围内不是静态的,即使它们将被分配给静态存储。例如,如果变量是类成员,则程序中的其他编译单元默认可以访问它,非类成员也不例外。

【讨论】:

  • 此外,假设全局声明的变量在 C++ 中默认是静态的,OP 是不正确的。它们具有外部链接,就像在 C 中一样。不过,全局变量在 C 和 C++ 中具有静态 duration,因此很容易混淆。
  • 所以规则适用于 *.c 和 *.cpp 文件,但不适用于 *.h 文件?谢谢!
  • 另一件重要的事情:如果他有多个来源,包括同一个标头,他的代码就会中断。
猜你喜欢
  • 2015-10-04
  • 2012-08-24
  • 2023-03-29
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-22
相关资源
最近更新 更多