You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#include"func1.h"intadd_2(int x, int y){
returnadd(x, y) + 1;
}
main.cpp
#include<iostream>
#include"func1.h"
#include"func2.h"usingnamespacestd;intmain(){
int x = 2, y = 3;
cout << add_2(x, y) << endl;
}
执行编译命令:g++ main.cpp -o main,编译出错:
In file included from main.cpp:2:
In file included from ./func2.h:1:
./func1.h:1:5: error: redefinition of 'add'
int add(int x, int y){
^
./func1.h:1:5: note: previous definition is here
int add(int x, int y){
^
1 error generated.
#ifndef FUNC1_H
#defineFUNC1_Hintadd(int x, int y){
return x + y;
}
#endif
func1.cpp
#include"func1.h"intadd_2(int x, int y){
returnadd(x, y) + 1;
}
main.cpp
#include"func1.h"
#include<iostream>usingnamespacestd;intadd_2(int x, int y);
intmain(){
int x = 2, y = 3;
cout << add_2(x, y) << endl;
}
执行编译命令g++ func1.cpp main.cpp -o main,编译报错如下
duplicate symbol 'add(int, int)' in:
/var/folders/2k/q001fz5n70j17wpl5v5lltxw0000gn/T/func1-3e6d02.o
/var/folders/2k/q001fz5n70j17wpl5v5lltxw0000gn/T/main-80fcd6.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
In the last example, I instead tried 'compile and then link', e.g.
g++ -c main.cpp func1.cpp
g++ main.o func1.o -o main
and here is my log
/usr/bin/ld: func1.o: in function `add(int, int)':
func1.cpp:(.text+0x0): multiple definition of `add(int, int)'; main.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit s
and here is my reasoning for this issue:
When compiled to machine code *.o and then link, the linker does not know that add is actually defined in the same file, e.g. func1.h, thus causing a duplicate function definition.
My question is:
Can I conclude that #ifndef or #pragma once lose their effect once it is compile into machine code? since if the still take effect the linker should be able to know add function has been defined in the first file.
As this problem can be addressed by deleting #include "func1.h" in main.cpp, which is symple, why should we only declare functions in *.h files rather than defining them?
宏定义的好处之一:宏定义的使用可以增加预编译指令,防止多次包含同一头文件时出现编译错误。
结论:在头文件中使用宏定义,可以使得头文件在一个源文件中被多次include时,同一段代码只被编译一次。一个头文件在不同的源文件中,依旧会被编译多次。因此若在头文件中定义函数或变量,即使头文件中使用了宏定义,头文件中的代码在多个源文件中依旧会被编译多次,导致链接时出错。
我们从下面的样例中进行分析:
func1.h
func2.h
main.cpp
执行编译命令:
g++ main.cpp -o main
,编译出错:In file included from main.cpp:2: In file included from ./func2.h:1: ./func1.h:1:5: error: redefinition of 'add' int add(int x, int y){ ^ ./func1.h:1:5: note: previous definition is here int add(int x, int y){ ^ 1 error generated.
原理:#include 指令将被包含的文件代码直接复制到当前文件,即 main.cpp 中的
#include "func1.h"
和#include "func2.h"
使得 main.cpp 等价为如下代码:因此,func1.h 在main.cpp中被重复包含,若无宏定义,则该段代码编译出错。宏定义即可解决该点问题,使得在main.cpp中func1.h的代码只被编译一次。即将func1.h修改为如下情况,则编译可以顺利通过
多个源文件包含func1.h:虽然宏定义解决上面单个文件中多次包含的问题,但依旧需要避免在头文件中进行变量定义及函数定义。
保留上述func1.h的实现不变,定义func1.cpp并修改main.cpp如下:
func1.h
func1.cpp
main.cpp
执行编译命令
g++ func1.cpp main.cpp -o main
,编译报错如下报错原因就是,在func1.cpp与main.cpp中,add函数被重复定义。宏定义作用范围仅为当前文件,无法跨文件起作用。即func1.cpp中的
#define FUNC1_H
与main.cpp中的#define FUNC1_H
不相关,分别仅在func1.cpp与main.cpp中有效。因此,宏定义可以解决单个源文件中某段代码被重复定义带来的错误。无法解决在多个源文件中重复include的问题。
The text was updated successfully, but these errors were encountered: