C++中的多重定义错误
Multiple definitions error in C++
我正在编写一个 C++ 程序,其中每个文件都有自己的一组全局变量声明。这些文件中的大多数都使用在其他文件中使用 extern 定义的全局变量。
这是一个类似于我的程序的例子:
Main.cpp
#include "stdafx.h"
#include <iostream>
#include "Other_File.cpp"
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
Other_File.cpp
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
当我在 Visual Studio (Windows) 中构建此代码时,一切运行良好且输出正确。但是当我尝试在 Linux 上使用 g++ 构建时,我收到以下错误:
g++ -o Testing Testing.o Other_File.o Other_File.o:(.bss+0x0):
multiple definition of var3' Testing.o:(.bss+0x0): first defined here
Other_File.o:(.bss+0x4): multiple definition of
var4'
Testing.o:(.bss+0x4): first defined here Other_File.o: In function
otherFunction()': Other_File.cpp:(.text+0x0): multiple definition of
otherFunction()' Testing.o:Testing.cpp:(.text+0x0): first defined
here collect2: ld returned 1 exit status make: *** [Testing] Error 1
这是因为我是 "including" 主文件中的另一个文件吗?
如果不是,我的代码有什么问题?
编辑:这是我的 g++ 生成文件的内容:
Testing: Testing.o Other_File.o
g++ -o Testing Testing.o Other_File.o
Testing.o: Testing.cpp
g++ -c -std=c++0x Testing.cpp
Other_File.o: Other_File.cpp
g++ -c -std=c++0x Other_File.cpp
clean:
rm *.o Calculator
不要 #include
将一个源文件插入另一个源文件。在某些时间和地点,这没问题,但只有不到 0.001% 的程序需要这样做。
您应该做的是创建一个 header 文件,其中包含两个源文件中所需内容的 声明。
那么您的代码将如下所示:
main.cpp
源文件
#include "stdafx.h"
#include <iostream>
#include "Other_File.h" // Note inclusion of header file here
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
}
other_file.cpp
源文件,就像你现在拥有的一样
other_file.h
header 文件,新文件
#pragma once
// Declare the variables, so the compiler knows they exist somewhere
extern int var3;
extern int var4;
// Forward declaration of the function prototype
void otherFunction();
然后两个源文件将分别编译并链接在一起形成最终的可执行文件。这个 linking 步骤是构建失败的地方。它会注意到 other_source.cpp
中定义的变量是在从该源文件创建的 object 文件中定义的,但是由于您将它包含在 main.cpp
源文件中,因此 object文件也是从该源文件创建的。
这就是为什么您需要了解 translation units, which is what the compiler actually see. A C++ source file goes through many phases of translation,每个人都各司其职。 翻译单元大致是包含所有header的单个源文件。
这也是了解 preprocessor #include
directive 功能的一个很好的理由。它基本上将包含的文件按原样插入到正在预处理的源文件中。在 #include
指令所在的位置,经过预处理后它将成为包含文件的内容,这就是编译器将看到的内容。
在编译器开始工作之前,包含有效地将包含文件粘贴到包含文件中,所以编译器看起来像这样:
#include "stdafx.h"
#include <iostream>
// #include "Other_File.cpp" sub in other file here
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
这本身不是问题。看起来很有趣,但这不是问题。没有重复的变量。
extern int var1;
告诉编译器在其他地方存在 var1
。稍后将找到并链接它。继续。如果你撒谎,链接器会抱怨。在这种情况下,大约有 10 行。
当 Other_File.cpp 被编译并链接到 Main.cpp 时,问题就来了。链接器在 Main.o 和 Other_File.o
中找到 var3
和 var4
的完整定义
您可以从构建中排除 Other_File.cpp,很可能是 Visual Studio 为您所做的,除了严重违反约定外,一切都会很好:永远不要包含 .cpp 文件。
为什么?因为按照惯例,cpp 文件定义了东西并使它们成为现实。通过在 header 中定义变量或函数,您可以同样糟糕地破坏 .h 文件。例如:
#ifndef BADHEADER_H_
#define BADHEADER_H_
int fubar; // don't do this
/* do this instead:
extern int fubar;
and place int fubar; into the most logical cpp file
*/
#endif /* BADHEADER_H_ */
每个包含 badheader.h 的人现在都有一个名为 fubar
的变量,无论他们是否需要,以及当链接器出现在 assemble 程序时,fubar
fubar
是真的吗?他们全部。哎呀。糟糕的链接器所能做的就是吐出一个错误并等待您修复歧义。
一天结束时,您可以 #include
任何事情。它不会编译,但您可以包含一个 Word 文档。你甚至可以表演
这样的小技巧
int array[] =
{
#include "filtercoefs.h"
};
其中 array.h 就是
1,2,3,4,5
当你有像 Matlab 这样的东西来输出滤波器系数时很有用,但更喜欢坚持惯例以防止你的同事之间的混淆。
无论如何,C++ 可以让你做各种各样的事情。他们中的大多数人在做之前最好考虑几次。
我正在编写一个 C++ 程序,其中每个文件都有自己的一组全局变量声明。这些文件中的大多数都使用在其他文件中使用 extern 定义的全局变量。
这是一个类似于我的程序的例子:
Main.cpp
#include "stdafx.h"
#include <iostream>
#include "Other_File.cpp"
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
Other_File.cpp
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
当我在 Visual Studio (Windows) 中构建此代码时,一切运行良好且输出正确。但是当我尝试在 Linux 上使用 g++ 构建时,我收到以下错误:
g++ -o Testing Testing.o Other_File.o Other_File.o:(.bss+0x0): multiple definition of
var3' Testing.o:(.bss+0x0): first defined here Other_File.o:(.bss+0x4): multiple definition of
var4' Testing.o:(.bss+0x4): first defined here Other_File.o: In functionotherFunction()': Other_File.cpp:(.text+0x0): multiple definition of
otherFunction()' Testing.o:Testing.cpp:(.text+0x0): first defined here collect2: ld returned 1 exit status make: *** [Testing] Error 1
这是因为我是 "including" 主文件中的另一个文件吗?
如果不是,我的代码有什么问题?
编辑:这是我的 g++ 生成文件的内容:
Testing: Testing.o Other_File.o
g++ -o Testing Testing.o Other_File.o
Testing.o: Testing.cpp
g++ -c -std=c++0x Testing.cpp
Other_File.o: Other_File.cpp
g++ -c -std=c++0x Other_File.cpp
clean:
rm *.o Calculator
不要 #include
将一个源文件插入另一个源文件。在某些时间和地点,这没问题,但只有不到 0.001% 的程序需要这样做。
您应该做的是创建一个 header 文件,其中包含两个源文件中所需内容的 声明。
那么您的代码将如下所示:
main.cpp
源文件#include "stdafx.h" #include <iostream> #include "Other_File.h" // Note inclusion of header file here int var1; int var2; int main() { var1 = 1; var2 = 2; otherFunction(); var4 = 4; // From Other_File.cpp std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl; }
other_file.cpp
源文件,就像你现在拥有的一样other_file.h
header 文件,新文件#pragma once // Declare the variables, so the compiler knows they exist somewhere extern int var3; extern int var4; // Forward declaration of the function prototype void otherFunction();
然后两个源文件将分别编译并链接在一起形成最终的可执行文件。这个 linking 步骤是构建失败的地方。它会注意到 other_source.cpp
中定义的变量是在从该源文件创建的 object 文件中定义的,但是由于您将它包含在 main.cpp
源文件中,因此 object文件也是从该源文件创建的。
这就是为什么您需要了解 translation units, which is what the compiler actually see. A C++ source file goes through many phases of translation,每个人都各司其职。 翻译单元大致是包含所有header的单个源文件。
这也是了解 preprocessor #include
directive 功能的一个很好的理由。它基本上将包含的文件按原样插入到正在预处理的源文件中。在 #include
指令所在的位置,经过预处理后它将成为包含文件的内容,这就是编译器将看到的内容。
在编译器开始工作之前,包含有效地将包含文件粘贴到包含文件中,所以编译器看起来像这样:
#include "stdafx.h"
#include <iostream>
// #include "Other_File.cpp" sub in other file here
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
这本身不是问题。看起来很有趣,但这不是问题。没有重复的变量。
extern int var1;
告诉编译器在其他地方存在 var1
。稍后将找到并链接它。继续。如果你撒谎,链接器会抱怨。在这种情况下,大约有 10 行。
当 Other_File.cpp 被编译并链接到 Main.cpp 时,问题就来了。链接器在 Main.o 和 Other_File.o
中找到var3
和 var4
的完整定义
您可以从构建中排除 Other_File.cpp,很可能是 Visual Studio 为您所做的,除了严重违反约定外,一切都会很好:永远不要包含 .cpp 文件。
为什么?因为按照惯例,cpp 文件定义了东西并使它们成为现实。通过在 header 中定义变量或函数,您可以同样糟糕地破坏 .h 文件。例如:
#ifndef BADHEADER_H_
#define BADHEADER_H_
int fubar; // don't do this
/* do this instead:
extern int fubar;
and place int fubar; into the most logical cpp file
*/
#endif /* BADHEADER_H_ */
每个包含 badheader.h 的人现在都有一个名为 fubar
的变量,无论他们是否需要,以及当链接器出现在 assemble 程序时,fubar
fubar
是真的吗?他们全部。哎呀。糟糕的链接器所能做的就是吐出一个错误并等待您修复歧义。
一天结束时,您可以 #include
任何事情。它不会编译,但您可以包含一个 Word 文档。你甚至可以表演
int array[] =
{
#include "filtercoefs.h"
};
其中 array.h 就是
1,2,3,4,5
当你有像 Matlab 这样的东西来输出滤波器系数时很有用,但更喜欢坚持惯例以防止你的同事之间的混淆。
无论如何,C++ 可以让你做各种各样的事情。他们中的大多数人在做之前最好考虑几次。