在使用C语言编写如下测试代码

1
2
3
4
5
6
7
8
9
10
11
//util.h
#ifndef __UTIL_H__
#define __UTIL_H__
#include <stdio.h>
void logInfo(char* msg)
{
printf("%s\n", msg);
}
#endif

1
2
3
4
5
6
7
8
9
10
11
12
13
//a.c
#include <stdio.h>
#include "util.h"
int max(int a, int b){
if(a == b){
logInfo("无法比较大小,因为他们一样大");
return -10000;
}
if(a > b){
return a;
}
return b;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//main.c
#include <stdio.h>
#include "util.h"
#include "a.c"
int main()
{
int a = 0;
int b = 0;
logInfo("请输入两个数字:");
scanf("%d",&a);
scanf("%d",&b);
int maxNum = max(a, b);
printf("最大的数:%d\n", maxNum);
}

编译出现下面的结果

1
2
3
4
5
6
7
[root@xxx abc]$ gcc main.c a.c util.h
/tmp/ccNHb71g.o: In function `logInfo':
a.c:(.text+0x0): multiple definition of `logInfo'
/tmp/ccLwg1eA.o:main.c:(.text+0x0): first defined here
/tmp/ccNHb71g.o: In function `max':
a.c:(.text+0x1a): multiple definition of `max'
/tmp/ccLwg1eA.o:main.c:(.text+0x1a): first defined here

分析之后发现原因为:
1、先有预处理程序把util.h分别包含进 main.c 和 a.c文件中。
2、由编译器和汇编器分别单独 编译+汇编 main.c a.c文件生成main.o 和a.o 到这里没有任何问题.
3、由连接器 ld 链接 main.o 和a.o 这里发现了重复定义的logInfo方法.


有几个规避该问题的方式
1、编译的时候直接 gcc main.c 这样就不会有a.c编译成a.o这一步骤。
2、将a.c改名为a.h,头文件是不会生成目标文件


总结

1
2
3
4
5
6
#ifndef _INCLUDE_NTREG_H
#define _INCLUDE_NTREG_H
//do something
#endif

只能保证在一个源文件中不会重复多次引用。
你现在是在两个c文件中,而且这两个文件要链接成一个可执行文件,就会有两处定义。
最佳实践是头文件不能有变量的定义,可以有声明。