【发布时间】:2015-12-09 04:41:45
【问题描述】:
我在空闲时间尝试了一些假 C,我发现了一些我觉得有趣的行为。我希望有人可以帮助回答我提出的一些问题。为了简单起见,让我们将讨论限制在使用 gcc 编译。首先,代码(.h 文件都有包含保护):
啊.h
void print_a();
b.h
void print_b();
c.h
void print_c();
交流
#include "a.h"
#include "c.h"
#include <stdio.h>
void print_c(){
printf("Printing c from a");
}
void print_a(){
print_c();
}
b.c
#include "b.h"
#include "c.h"
#include <stdio.h>
void print_c(){
printf("Printing c from b");
}
void print_b(){
print_c();
}
main.c
#include "a.h"
#include "b.h"
int main(int argc, char **argv){
print_a();
print_b();
return 0;
}
首先,我知道 a.c 和 b.c 都有 c.h 的实现。因此,我预计这样的编译会失败,因为编译器不知道 print_c 的哪个实现要绑定到接口:
gcc main.c a.c b.c
但是您会注意到 main.c 对 c.h 没有依赖关系。因此,在单独编译每个组件时,看到在链接器阶段失败,我有点惊讶:
gcc -c a.c
gcc -c b.c
gcc -c main.c
gcc main.o a.o b.o
b.o: In function `print_c':
b.c:(.text+0x0): multiple definition of `print_c'
a.o:a.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
很明显,由于链接器还没有链接 print_c 的定义,所以我们仍然应该预料到这些错误。也就是说,我可以想到几个实际的用例,这些用例会出现问题。例如,如果我在我的程序中使用了 log.h 接口的一些自定义实现,但我想包含一个在内部实现相同 log.h 接口的库,该怎么办?这引出了我的问题:
- 有没有办法在单个文件上运行链接器以生成某种中间链接文件,然后在另一个链接步骤中组合它们?
- 作为上述的替代方案,一个定义良好的 C 应用程序是否会避免使用任何像这样的共享头文件?
- 如果是这样,如果多个依赖项的方法定义相同但实现不同怎么办?如果从源代码编译依赖项,显然可以重命名函数,但在不可能的情况下,这将如何工作?
- 这甚至是 C 语言中的问题吗?我来自 OO 背景,这样的问题并不真正存在,但这似乎是抽象的明显障碍。我很可能只是遗漏了一些可以防止此问题的常见内容(如方法命名约定等)。
【问题讨论】: