在main()与global中定义extern变量

时间:2012-06-01 05:26:01

标签: c++ extern

给定以下头文件,如果在主体内部定义'a',我会收到警告“未使用的变量'a'”和链接器错误“未定义引用'a'。

header.h:

#ifndef HEADER_H
#define HEADER_H

#include <iostream>

extern int* a;

void f()
{
    std::cout<<*a <<std::endl;
    return;
}

#endif

main.cpp中:

#include "header.h"

int main()
{
    int* a = new int(10);

    f();
}

但是,如果在main()之外定义'a',则程序链接没有错误,f()按预期工作(打印10)。为什么是这样?

示例:

int* a = new int(10);

int main()
{
    f();
}

6 个答案:

答案 0 :(得分:3)

int* a = new int(10);

对于这一行,如果在main函数中,则定义一个局部变量。

所以extern int* a;只声明一个变量,但不定义它。然后在该符号上获得链接错误

答案 1 :(得分:2)

在main中定义变量时,它只在main函数中有作用域。 全球外部人士无法解决这个问题。换句话说,链接器不能将全局声明的extern与main函数内的变量定义匹配。

答案 2 :(得分:2)

阅读4个解释错误的答案是相当烦人的,但没有人解释如何正确解决问题。这可能是一个安全的猜测,如果OP不知道范围界定,他可能也不知道将变量传递给函数。

问题

您试图获取变量的值,但该变量位于另一个函数中。我怎么能得到它?嗯,简单的答案是,你不想得到它。你听到我说得对。使用函数的全部原因是可重用性,如果将新创建的函数绑定到另一个函数,则无法在任何地方使用它。记住,功能可以帮助你变懒。一个优秀的程序员是一个懒惰的程序员。如果你可以编写一个函数并在一百万个地方使用它,那么你做得对。 ;)

但我仍然希望得到该变量的值

然后你想使用函数参数将变量传递给函数。

命名函数是因为你可以用数学来思考它们。将变量放入,在函数运行后获取有用的数据,并使用这些变量完成有趣的事情。所以假设你有一个数学函数y = f(x),相当于int f(int x) { /*stuff here*/ }然后你使用int y = f(a)在主函数中调用它,其中a是一些变量或数字

你想要避免使用全局变量,因为它们并不总能达到预期的效果(特别是如果你有很多代码,很容易意外地使用相同的名称。)

在你的情况下,你希望函数打印出特定变量的内容,所以我想也许你正在寻找一种方法将该函数与任何特定变量一起使用。所以这就是你如何做到的。

void f(); //hi, I'm a function prototype
void f(int a); //hi, I'm a function prototype that takes a parameter
void f(int a, int b); //hi, I'm a function prototype that takes two parameters (both ints)
void f(int a, ...); //hi, I'm a function prototype that takes an int then any number of extra parameters (this is how printf works.)

所以你真正想要的是将你的代码改为:

header.h:

#ifndef HEADER_H
#define HEADER_H

#include <iostream>

// extern int* a; // We don't need this

void f(int* a)
{
  if (a != NULL) //always, always check to make sure a pointer isn't null (segfaults aren't fun)
    std::cout<<*a <<std::endl;
    //return;  //Don't really need this for a function declared void.
}

#endif

main.cpp中:

#include "header.h"

int main()
{
    int* a = new int(10);

    f(a);
    return 0; //main is declared as returning an int, so you should.
}

按值,指针和参考的功能

因此,在您的示例中,我在您的示例中使用了int而不是int*。两者之间的区别是第一个通过值传递参数。另一个是指针。将变量传递给函数时,始终会复制它。如果你传递一个int,它会生成一个int的副本,如果你传递一个4 MB的结构,它将复制4MB结构,如果你传递它一个4MB结构的指针将复制一个指针(不是整个结构。)这有两个重要原因:

  1. 性能:制作4MB结构的副本需要一些时间。
  2. 更改内容的能力:如果您复制指针,原始数据仍然在同一个位置,仍可通过指针访问。
  3. 如果您想要1而不是2,该怎么办?那么你可以声明指针const。原型如下所示:int f(int const* a);

    如果您想要2而不是1,该怎么办?坚韧的饼干(无论如何都没有充分的理由。)

    最后,您还可以声明一个函数来获取引用而不是指针,引用和指针之间的最大区别是引用不会为NULL(并且您不能在引用上使用指针算法。)您将希望使用通过引用传递或通常传递值。需要传递指针是我几乎不需要做的事情,根据我的经验,它更像是一种特殊情况。

    通过引用传递:int f(int& a);
    通过const引用:int f(int const& a);

    总结一下:

    if you have function that needs parameters:
      then:
        if you do not need to modify the contents:
          then:
            if the size of the variable is small:
              pass by value: int f(int a);
            else if the size of the variable is large:
              then:
                if the value of the address can be NULL:
                  pass by const pointer: int f(int const* a);
                else:
                  pass by const reference: int f(int const& a);
        else if you do need to modify the contents:
          then:
            if the value of the address can be NULL:
              pass by pointer: int f(int* a);
            else:
              pass by reference: int f(int& a);
    

    还有一些案例,但这些是主要案例,请参阅this website for more details.

答案 3 :(得分:2)

您需要了解名称绑定,它决定了两者的名称 相同名称的声明是相关的。定义变量时 在一个函数内,它的名字没有联系;即它所指的实体 与计划中的任何其他实体不同。

更一般地说:一个声明(在这个意义上,定义也是一个 声明)将一个符号与一个实体 - 一个对象(在 在哪种情况下,声明声明一个变量),一个函数,一个 引用,类型或您可以在C ++中声明的任何其他内容。是否 同名的不同声明与同一实体关联 是否由链接定义。 C ++识别三个 不同类型的联系:

  • 外部链接,其中实体可以通过其他转换单位的声明引用,

  • 内部链接,其中实体可由同一翻译单位中的其他声明引用,

  • 无链接,其中任何其他声明都不能引用该实体。

在块范围内声明的变量(即局部变量)没有 链接,除非明确声明extern(和本地 变量声明extern不能是定义)。所以int amain声明(并定义)一个独立于任何实体的实体 程序中的其他a。在命名空间范围内声明的变量具有 外部链接,除非它们被声明static,在这种情况下它们 有内部联系;当你在命名空间范围定义int a时,它 具有外部链接,因此引用您声明的同一实体 标题中为extern int a

答案 4 :(得分:1)

如果您在a内定义main,则其范围(可见性)仅限于main - extern声明将让它在其他地方可见。

您必须在命名空间范围内(即在任何函数之外)定义它,以使其在其他翻译单元中可见。

答案 5 :(得分:1)

在函数main中定义变量时,它仅在main的范围内有效。您可以在所有函数中定义名为a的变量。但这些是不同的变量,因为每个变量都有它的范围。

从技术上讲,在调用函数时,变量是在堆栈上分配的,因此每个实例都有自己的存储。