gpt4 book ai didi

c - 具有 "Independent"目标文件的多个定义

转载 作者:太空宇宙 更新时间:2023-11-04 04:32:42 37 4
gpt4 key购买 nike

我一直在空闲时间尝试伪造 C,并且遇到了一些我觉得很有趣的行为。我希望有人能帮助回答我提出的一些问题。为了简单起见,让我们将讨论限制在使用 gcc 进行编译。首先是代码(.h文件都有include guards):

啊.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();
}

BC

#include "b.h"
#include "c.h"

#include <stdio.h>

void print_c(){
printf("Printing c from b");
}

void print_b(){
print_c();
}

ma​​in.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 的哪个实现绑定(bind)到接口(interface):

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 接口(interface)的一些自定义实现,但我想包含一个在内部实现相同 log.h 接口(interface)的库怎么办?这引出了我的问题:

  • 有没有办法在单个文件上运行链接器以生成某种中间链接文件,然后在另一个链接步骤中组合它们?
  • 作为上述方法的替代方案,一个定义良好的 C 应用程序是否会避免使用任何共享头文件,就像这样?
    • 如果是这样,如果多个依赖项具有定义相同但实现不同的方法怎么办?如果从源代码编译依赖项,显然可以重命名函数,但在不可能的情况下如何工作?
  • 这甚至是 C 中的问题吗?我来自 OO 背景,像这样的问题实际上并不存在,但这似乎是抽象的明显障碍。很可能我只是遗漏了一些可以防止出现此问题的常见内容(例如方法命名约定等)。

最佳答案

头文件包含函数原型(prototype)。函数原型(prototype)告诉编译器

  • 函数名称
  • 函数接受的参数
  • 函数的返回类型

按照惯例,头文件仅包含在一个源文件中定义但在其他源文件中使用的函数的函数原型(prototype)。

所以c.h不应该存在,a.hb.h中的函数原型(prototype)需要参数列表。头文件应该是:

啊.h

void print_a( void );

b.h

void print_b( void );

源文件a.cb.c 可以改进如下。首先,始终在您自己的 header 之前包含标准 header (请参阅下面的注释)。其次,不需要包含 c.h,因为 print_c 在使用之前已定义。所以函数定义作为函数原型(prototype)。第三,print_c 需要一个参数列表:void print_c( void )第四,也是重点,print_c函数要声明为staticstatic关键字表示该函数仅在定义它的文件中可见,即它不是全局可见的。使用 static 关键字允许您在每个 .c 文件中重新定义函数。

所以你的源文件应该是这样的

交流

#include <stdio.h>
#include "a.h"

static void print_c( void ){
printf("Printing c from a\n");
}

void print_a( void ){
print_c();
}

BC

#include <stdio.h>
#include "b.h"

static void print_c( void ){
printf("Printing c from b\n");
}

void print_b( void ){
print_c();
}

ma​​in.c

#include "a.h"
#include "b.h"

int main( void ){
print_a();
print_b();
return 0;
}

注意:首先包含标准头文件的原因是标准头文件应该没有错误,而您的头文件可能没有。如果您的 header 中存在语法错误,并且您的 header 包含在标准 header 之前,则该错误最终可能会被报告为标准 header 中的错误,这会变得非常困惑。

关于c - 具有 "Independent"目标文件的多个定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34170867/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com