我正在尝试理解全局变量和函数如何在C中工作。我的程序使用gcc
编译并正常工作,但不能使用g++
进行编译。我有以下文件:
globals.h:
int i;
void fun();
globals.c:
#include "stdlib.h"
#include "stdio.h"
void fun()
{
printf("global function\n");
}
main.c中:
#include "stdlib.h"
#include "stdio.h"
#include "globals.h"
void myfun();
int main()
{
i=1;
myfun();
return 0;
}
最后, myfun.c :
#include "stdlib.h"
#include "stdio.h"
#include "globals.h"
void myfun()
{
fun();
}
使用g ++编译时出现以下错误:
/tmp/ccoZxBg9.o:(.bss+0x0): multiple definition of `i'
/tmp/ccz8cPTA.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
任何想法为什么?我宁愿用g ++编译。
答案 0 :(得分:6)
包含globals.h的每个文件都将定义“int i”。
相反,把“extern int i;”进入头文件然后把实际定义“int i = 1;”在globals.c中。
在globals.h周围设置标题保护也是明智的。
编辑:在回答您的问题时,因为#include的作用类似于剪切和粘贴。它将包含文件的内容粘贴到您调用的c文件中。当您从main.c和myfun.c中包含“globals.h”时,您将在两个文件中定义int i = 1。这个全局的值被放入可链接值表中。如果你有两次相同的变量名,那么链接器就无法分辨出它需要哪一个,你就会得到你看到的错误。而是通过在头文件的前面添加extern,您告诉每个文件“int i”在其他地方定义。显然,你需要在其他地方定义它(并且只在一个地方),所以在globals.c中定义它是完全合理的。
希望有所帮助:)
答案 1 :(得分:1)
我会在你的全局文件中添加一个include guard
#ifndef GLOBALS_H
#define GLOBALS_H
int i;
void fun();
#endif
编辑:将你的全局变更为这样(使用extern作为另一个答案描述)
globals.h
extern int i;
extern void fun();
globals.c
#include "stdlib.h"
#include "stdio.h"
int i;
void fun()
{
printf("global function\n");
}
我用
编译了它g++ globals.c main.c myfun.c
它运行正常
答案 2 :(得分:1)
这里有些不对劲;其他一些强烈推荐的事情:
globals.h:
#ifndef GLOBALS_H
#define GLOBALS_H
extern int my_global;
#ifdef __cplusplus
extern "C" {
#endif
void fun();
#ifdef __cplusplus
}
#endif
#endif
/* GLOBALS_H */
globals.c:
#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
int my_global;
void fun()
{
printf("global function: %d\n", my_global);
}
main.c中:
#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
void myfun();
int main()
{
my_global=1;
myfun();
return 0;
}
void myfun()
{
fun();
}
你应该在标题中声明“extern int myvar”,并在一个且只有一个.c文件中实际分配“int myvar”。
您应该在每个使用“myvar”的文件中包含“globals.h” - 包括分配它的文件。
特别是如果你计划混合使用C和C ++模块,你应该使用'extern“C”来区分非C ++函数。
系统标题应为“#include&lt; some_header.h&gt;”;你自己的标题应该使用引号(#include“myheader.h”)代替。
像“i”这样的短变量名称对于严格的局部变量(如循环索引)可能没问题,但是只要你不能避免使用全局变量,就应该总是使用更长的描述性名称。
我为my_global添加了“printf”。
'希望有所帮助!
答案 3 :(得分:0)
将一些旧的C代码移植到C ++时遇到了这个问题。问题是它是一个连接到数据库的项目,我想将数据库移植到c ++而不是其余的。数据库引入了一些无法移植的C依赖项,因此我需要与数据库和其他项目重叠的C代码,以g ++和gcc编译......
此问题的解决方案是将所有变量定义为.h文件中的 extern 。然后当你用gcc或g ++编译时,它会报告.c文件中缺少的符号。因此,请编辑错误消息中的.c文件,并将声明插入所有 <。 变量的.c文件中。注意:您可能必须在多个.c文件中声明它,这就是我扔的原因以及为什么我长期坚持这个问题。
无论如何,这解决了我的问题,代码现在在gcc和g ++下干净利落地编译。