c - 编译器如何选择链接哪个函数?

标签 c linker

我有一个程序(main.c):

#include <stdio.h>
#include <math.h>

int main() {
    int result = sqrt(9);
    printf("result: %d\n" ,result);
    return 0;
}

double sqrt(double blah) {
    return 0;
}

当我运行这个时,我的结果是

result: 3

这会告诉我链接器正在选择 libm 库的 sqrt 函数而不是我的函数来调用我的 main 函数。

在启用所有警告的情况下编译此程序时,我没有收到任何错误或警告:

gcc main.c -Wall

我的问题:

  • 为什么链接器不选择我定义的 sqrt 来调用?
    • 这是确定性的吗?
  • 为什么我没有收到任何错误或警告?具有相同签名的函数的多个定义似乎是一个陷阱,应该以某种方式指出。
  • 有没有办法输出哪些函数链接到哪里?那么,如果我遇到引用了非预期定义的情况,我可以调试吗?

我唯一能想到的是当我运行 gcc --precompile 时,我看到了这个函数声明:

extern double sqrt(double);

这是否告诉链接器 sqrt 是在该文件之外定义的?并且由于这已经满足sqrt的定义,所以在链接时忽略我自己的定义?

gcc 信息(我知道它真的很响,因为我在 mac 上,不确定这是否对这个问题有影响)

gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

编辑:

汇编输出:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 15    sdk_version 10, 15
    .section    __TEXT,__literal8,8byte_literals
    .p2align    3               ## -- Begin function main
LCPI0_0:
    .quad   4621256167635550208     ## double 9
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movsd   LCPI0_0(%rip), %xmm0    ## xmm0 = mem[0],zero
    movl    $0, -4(%rbp)
    sqrtsd  %xmm0, %xmm0
    cvttsd2si   %xmm0, %eax
    movl    %eax, -8(%rbp)
    movl    -8(%rbp), %esi
    leaq    L_.str(%rip), %rdi
    movb    $0, %al
    callq   _printf
    xorl    %esi, %esi
    movl    %eax, -12(%rbp)         ## 4-byte Spill
    movl    %esi, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .globl  _sqrt                   ## -- Begin function sqrt
    .p2align    4, 0x90
_sqrt:                                  ## @sqrt
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movsd   %xmm0, -8(%rbp)
    xorps   %xmm0, %xmm0
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "result: %d\n"


.subsections_via_symbols

最佳答案

标准 C 库函数的名称保留用作外部链接的标识符。您不应该将它们用于您自己的功能。这意味着当您使用保留名称时,编译器可能会假定它是标准函数,而不是您自己的实现。然后,为了优化您的程序(即使没有打开完全优化),编译器可能会用处理器的平方根指令替换对 sqrt 的调用。或者编译器甚至可以自己计算结果并将其构建到汇编代码中。

关于c - 编译器如何选择链接哪个函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69095865/

相关文章:

c - 请解释此代码如何去除图像中的噪声

c++ - 直接用变量设置指针意味着什么?

c - 在单个遍历链表中交换从开始到结束的第 k 个位置

c - 如何使这个函数定时宏在 C 中工作?

c++ - 在 C++ 程序上使用 mpicc 链接失败

c - 奇怪的输出?

xcode - 复杂的静态库链接

c - 如何用从偶数地址边界开始的两个字节值填充 S-record?

objective-c - 添加一个大的静态库作为 cocoapod 或直接将所有目标文件添加到生成的二进制文件中,因为 -ObjC 链接器标志

c++ - 跟踪器示例中的 OpenCV 3.0 链接器错误