如何在多个文件中使用变量?

时间:2012-11-03 13:08:02

标签: c++ c static include makefile

我想在标题中定义一个变量,并能够在多个文件中使用它。 例如在某处定义变量a并且能够在p1.cpp和p2.cpp中使用/更改它

以下是我正在尝试的3个简单文件的示例。

// vars.hpp
#ifndef VARS_HPP
#define VARS_HPP

int a = 1;
float b = 2.2;
void double_vars();

#endif



// vars.cpp
#include "vars.hpp"
void double_vars () {
    a *= 2;
    b *= 2;
}

// vars_main.cpp
#include <cstdio>
#include "vars.hpp"
int main () {
    printf("a: %d; b: %f\n", a, b);
    double_vars();
    printf("a: %d; b: %f\n", a, b);
}

现在,用以下内容编译上述内容:

g++ -Wall -W -g vars.cpp vars_main.cpp -o vars && ./vars

给了我以下错误:

/tmp/ccTPXrSe.o:(.data+0x0): multiple definition of `a'
/tmp/ccnc1vof.o:(.data+0x0): first defined here
/tmp/ccTPXrSe.o:(.data+0x4): multiple definition of `b'
/tmp/ccnc1vof.o:(.data+0x4): first defined here

有人可以向我解释为什么会这样吗?我在头文件中有警卫,所以据我所知它应该只包含一次所以不应该有多个声明

3 个答案:

答案 0 :(得分:4)

在头文件中,写下:

extern int a;
extern float b;

这将声明变量。

在其中一个CPP文件中,写下:

int a = 1;
float b = 2.2;

这将定义变量。只要变量只定义一次就无论在哪个CPP文件中放置定义都无关紧要。

答案 1 :(得分:4)

首先,不要这样做。全球可变状态通常是一件坏事。

问题是,一旦链接器完成了你的include语句中的文件组合,它已经看过两次了,一次在main.cpp中,一次在vars_main.cpp中:

int a = 1;
float b = 2.2;

如果您只将其放在头文件中,它会以多个翻译单位显示,每个cpp文件包含您的标题一次。编译器不可能知道你在说什么a和b。

解决此问题的方法是在标题中声明extern

extern int a;
extern float b;

这告诉编译器a和b在某处定义,不一定在代码的这一部分。

然后,在您的一个cpp文件中,您将定义它们:

int a = 1;
float b = 2.2;

这样,ab存储有一个明确定义的存放位置,编译器可以正确连接点。

答案 2 :(得分:1)

Collin已经描述了问题和解决方案,但我想强调一下它的风格有多糟糕。

正如你从这个简单的练习中发现的那样,以这种方式使用全局变量通常是一件坏事。除了您已经发现的编译器问题之外,使用全局变量在函数之间共享状态会导致以下问题:

  • 它使得函数本身更难在其他程序中重用,因为函数期望存在这些符号;

  • 对一个函数的更改可能会导致共享该状态的其他函数出现问题(即,更改未本地化为该函数);

  • 代码变得更难调试,因为任何人都可以随时修改ab

理想情况下,函数应该通过参数,返回值和异常(如果适用)进行通信;有时候共享状态是正确的答案,但是那些相对较少且相差甚远。

由于你显然使用的是C ++编译器,我将采用C ++方式,使用引用而不是指针。我也将使用C ++ iostream例程而不是cstdio(编写C或C ++;尝试将两者混合起来导致胃灼热)。

vars.hpp:

#ifndef VARS_H  // Include guard to prevent multiple inclusion
#define VARS_H

void double_vars(int &, float &);

#endif

vars.cpp:

#include "vars.hpp"

void double_vars(int &x, float &y)
{
  x *= 2;    
  y *= 2.0;  
}

main.cpp中:

#include <iostream>
#include "vars.hpp"

int main(void)
{
  int a = 1;
  float b = 2.2;

  std::cout << "a: " << a << "; b: " << b << std::endl;
  double_vars(a, b);
  std::cout << "a: " << a << "; b: " << b << std::endl;

  return 0;
}

由于xy被声明为引用类型(使用&),因此写入表达式 {{ {}}和x中的y相当于在double_vars中写入ab

这样做的方法是使用指针而不是引用:

vars.h:

main

vars.c:

#ifndef VARS_H  // Include guard to prevent multiple inclusion
#define VARS_H

void double_vars(int *, float *); 
#endif

main.c中:

#include "vars.h"

void double_vars(int *x, float *y)
{
  *x *= 2;    
  *y *= 2.0;  
}

在这种情况下,我们使用指针而不是引用,因此我们需要将表达式 #include <stdio.h> #include "vars.h" int main(void) { int a = 1; float b = 2.2; printf("a: %d; b: %f\n", a, b); double_vars(&a, &b); printf("a: %d; b: %f\n", a, b); return 0; } &a的结果传递给&b ;在函数内,写入double_vars*x表达式与写入*y中的ab相同。