我不确定我在这里做错了什么:我有3个.cpp文件:main_program.cpp、read_input_data.cpp、write_output_data.cpp。 主程序调用两者,readinputdata读取字符串,writeoutputdata将其写出。数据被读入 INPUT.h 中命名空间“INPUTDATA”中定义的
string garbage
,而函数则在“FUNCTIONS.h”中声明。
这是我得到的错误:
g++ -o f2d ../obj/main_program.o ../obj/read_input_data.o ../obj/write_output_data.o -Wall -Wextra -O3 -Werror -pedantic -Ofast
/usr/bin/ld: ../obj/read_input_data.o:(.bss+0x0): multiple definition of `INPUTDATA::garbage[abi:cxx11]'; ../obj/main_program.o:(.bss+0x0): first defined here
/usr/bin/ld: ../obj/write_output_data.o:(.bss+0x0): multiple definition of `INPUTDATA::garbage[abi:cxx11]'; ../obj/main_program.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:20: f2d] Error 1
这就是我的文件的样子: 主程序.cpp
// main_program.cpp
// libraries to include
#include <iostream>
#include <fstream>
#include <string> //Wheres Wallace????
// header files
#include "../headers/INPUT.h"
#include "../headers/FUNCTIONS.h"
using namespace INPUTDATA;
using namespace std;
int main()
{
read_input_data();
write_output_data();
return 0;
}
读取输入数据.cpp
#include <iostream>
#include <string> //Wheres Wallace????
#include "../headers/INPUT.h"
#include "../headers/FUNCTIONS.h"
using namespace std;
using namespace INPUTDATA;
void read_input_data()
{
cin>>garbage;
}
写入输出数据.cpp
#include <iostream>
#include <string> //Wheres Wallace????
#include "../headers/INPUT.h"
#include "../headers/FUNCTIONS.h"
using namespace std;
using namespace INPUTDATA;
void write_output_data()
{
cout<<garbage<<endl;
}
输入.h
#ifndef INPUT_H // include guard
#define INPUT_H
#pragma once
#include <string> //Wheres Wallace????
using namespace std;
namespace INPUTDATA
{
string garbage;
}
#endif
函数.h
#ifndef FUNCTIONS_H // include guard
#define FUNCTIONS_H
#pragma once
void read_input_data();
void write_output_data();
#endif
这是我的 makefile,但我不认为它是 makefile,因为我也使用它测试了一个单独的代码:
IDIR =../headers
CXX=g++
CFLAGS=-Wall -Wextra -O3 -Werror -pedantic -Ofast
HDIR=../headers
DEPSNAME = INPUT.h FUNCTIONS.h
DEPS = $(patsubst %,$(HDIR)/%,$(DEPSNAME))
ODIR=../obj
OBJNAME = main_program.o read_input_data.o write_output_data.o
OBJ = $(patsubst %,$(ODIR)/%,$(OBJNAME))
$(ODIR)/%.o: %.cpp $(DEPS)
$(CXX) -c -o $@ $< $(CFLAGS)
all: f2d
f2d: $(OBJ)
$(CXX) -o $@ $^ $(CFLAGS)
.PHONY: clean
clean:
rm -f f2d $(ODIR)/*.o *~ core $(INCDIR)/*~
我真的不知道我在这里做错了什么。如果有人可以帮忙,我将不胜感激。谢谢!
我希望错误不会发生。
garbage
是在头文件中定义的全局变量。每个不同的 .cpp
文件称为编译单元,因为它们是单独编译的。一旦编译单元被编译,它就会创建一个目标文件(每个 .o
文件)。
考虑一下,当您包含一个文件时,从编译器的角度来看,这就像头文件的内容被“复制粘贴”到
.cpp
文件中一样,因此所有包含文件的所有内容构成包含它们的所有编译单元的一部分。
由于所有翻译单元(又名
.cpp
文件)都包含 INPUT.h
,编译器将在生成的每个 garbage
中多次定义全局变量 .o
,因此所有 .o
文件都将具有其自己的 garbage
全局变量的“副本”。
因此,您最终声称正在定义一个名为
garbage
的全局(因此是单个)变量,但该变量最终被定义多次,这违反了单定义规则 (ODR),因为必须只有同一实体的一种定义(全局的,但同样适用于函数)。这是由链接器检测到的(在 makefile 的 f2d
规则中),该软件尝试将所有 .o
合并到单个可执行文件中。
在
extern
前面写下string garbage
,如下所示:
namespace INPUTDATA
{
extern string garbage;
}
这样,您就可以向编译器明确声明
garbage
不会“在此编译单元中”定义,而是在某个“外部”位置定义,仍然允许编译器知道该变量存在。现在使用以下命令创建 INPUT.cpp
:
#include "INPUT.h"
namespace INPUTDATA
{
string garbage;
}
你就完成了。