这个C程序如何编译和运行两个主要功能?

MrP*_*ayi 65 c gcc program-entry-point

今天,在使用一个自定义库时,我发现了一种奇怪的行为.静态库代码包含调试main()功能.它不在#define旗帜内.所以它也存在于库中.它被用于链接到包含真实的另一个程序main().
当它们都链接在一起时,链接器不会抛出多个声明错误main().我想知道这是怎么发生的.

为简单起见,我创建了一个模拟相同行为的示例程序:

$ cat prog.c
#include <stdio.h>
int main()
{
        printf("Main in prog.c\n");
}

$ cat static.c
#include <stdio.h>
int main()
{
        printf("Main in static.c\n");
}

$ gcc -c static.c
$ ar rcs libstatic.a static.o
$ gcc prog.c -L. -lstatic -o 2main
$ gcc -L. -lstatic -o 1main

$ ./2main
Main in prog.c
$ ./1main
Main in static.c
Run Code Online (Sandbox Code Playgroud)

"2main"二进制文件如何找到main要执行的内容?

但是将它们编译在一起会产生多重声明错误:

$ gcc prog.c static.o
static.o: In function `main':
static.c:(.text+0x0): multiple definition of `main'
/tmp/ccrFqgkh.o:prog.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释这种行为吗?

ars*_*rsv 57

引用ld(1):

链接器将仅在命令行上指定的位置搜索一次存档.如果存档定义了在命令行上存档之前出现的某个对象中未定义的符号,则链接器将包含存档中的相应文件.

当链接2main时,主符号在ld到达-lstatic之前被解析,因为ld从prog.o中获取它.

链接1main时,在到达-lstatic时,确实有未定义的main,因此它会在归档中搜索main.

此逻辑仅适用于归档(静态库),而不适用于常规对象.链接prog.o和static.o时,无条件地包含来自两个对象的所有符号,因此会出现重复的定义错误.

  • 请注意,此行为是特定于编译器的(或者,特定于链接器):Microsoft链接器将在其命令行上搜索所有目标文件和库,如果符号重复,则会发生错误. (14认同)

P.P*_*.P. 17

链接静态库(.a)时,链接器仅搜索存档,如果到目前为止已跟踪任何未定义的符号.否则,它根本不会查看存档.所以你的2main情况下,它从不查看存档,因为它没有任何未定义的符号来制作翻译单元.

如果您包含一个简单的函数static.c:

#include <stdio.h>
void fun()
{
      printf("This is fun\n");
}   
int main()
{
      printf("Main in static.c\n");
}
Run Code Online (Sandbox Code Playgroud)

并且从中调用它prog.c,然后链接器将被强制查看存档以找到符号,fun并且您将获得相同的多个主要定义错误,因为链接器main现在会找到重复的符号.

直接编译目标文件时(如gcc a.o b.o),链接器在这里没有任何作用,并且包含所有符号以生成单个二进制文件,并且显然存在重复的符号.

底线是链接器仅在缺少符号时才查看存档.否则,它与不与任何库链接一样好.