为什么函数定义的顺序会改变输出二进制文件?

4

给定这两个C程序

函数原型和声明
after.c

#include<stdio.h>
void hi();
int main(){
  hi();
  return 0;
}
void hi(){
  puts("hello world");
}

仅函数定义
before.c

#include<stdio.h>
void hi(){
  puts("hello world");
}

int main(){
  hi();
  return 0;
}

编译命令如下:
cc -oafter after.c
cc -obefore before.c

md5sum *
efac7a08389095a718b7fc9e163719ca after
41e81298acdf96091b4a9326a4557b0c after.c
d5b87a14479e764f1c8a8669182773a1 before
924ec57ea6ef7ee306edfd0ec7f5fd54 before.c

可以看到,这将产生不同的二进制文件。为什么会这样?before和after有什么不同之处?是否存在速度差异?


1
地址链接改变?我不认为其中一个版本应该比另一个版本更快。 - πάντα ῥεῖ
“哪个更快?”只是意味着“我还没有对自己的代码进行性能分析”。所以不要问那个;-) 我建议你对 ELF 二进制格式(或者你的系统使用的任何二进制格式)进行一些研究,这将让你了解二进制文件需要包含什么。 - Rook
我认为在第一个程序的输出汇编中,主函数将出现在函数之前,在最后一个程序的输出中,函数“hi”位于“main”之前。 - phuclv
1个回答

4
没有要求编译器/链接器工具链为等效程序生成具有相同校验和的可执行文件。实际上,在某些平台上,当重新构建“相同程序”时,某些编译器会生成不同的可执行文件。
例如,请参见每次重新编译后exe校验和都不同 您必须对可执行文件进行分析,以查看是否存在性能差异(在您的示例中,几乎肯定没有差异)。

当同一程序被重建两次时。这种情况特别容易发生在那些将编译日期/时间、构建编号等信息放入所谓“清单”中的系统中。 - πάντα ῥεῖ
但是这两个程序几乎完全相同,除了它们的顺序之外没有任何变化。 - user1461607
1
@user1461607 简单来说,二进制中函数的顺序与代码中函数的顺序相匹配。(这不是普遍真理,但编译器可能会以这种方式工作。)如果在您的系统上是这种情况,那么您就知道为什么事情会有所不同了。 - glglgl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接