为什么在Linux上编译的程序不能在Windows上运行?

16

我几乎可以确定我的问题是由于编译后的程序被编译为Linux可执行文件,但我想再次确认一下。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("Hello world!\n");
    return EXIT_SUCCESS;
}

上述的"程序"应该可以在Windows和Linux上编译通过,因为它是源代码兼容的,没有任何特定于操作系统的库或类似的东西。

然而,在我的Linux系统上键入 "c99 hello.c -o hello.exe",然后将该"可执行文件"转移到Windows机器上时,它拒绝运行。据我所知,Linux生成的可执行文件只能在Linux上运行,因此添加 ".exe" 没有效果。要在Linux上为Windows构建该程序,我需要在Windows机器上重新编译该程序吗?还是有其他更简单的方法可行?


9
你的理解基本上是正确的。不同操作系统上可执行文件的格式和执行方式也不同。 - Eugene Sh.
2
另一种方法称为“交叉编译”。 - Eugene Sh.
2
回答标题问题:同样的原因,柴油发动机不能使用无铅汽油,反之亦然。它们是不同的系统。 - Jens
2
除了不同的文件格式(在Windows上是ELF vs.“可移植可执行文件”格式),这两个操作系统还具有不同的应用程序二进制接口(ABI)。 - Andre Holzner
1
没有操作系统特定的库。printf是用来干什么的?每个系统都使用不同的方式将字符打印到控制台。此外,不仅二进制格式不同,ABI也不同。 - phuclv
显示剩余2条评论
2个回答

29

Windows和Linux可执行文件使用两种不兼容的格式:

在Windows上,它是Portable Executable格式

在Linux上,它是ELF(可执行可链接格式)

每种格式都利用了它们所运行的操作系统的特殊性,因此通常不能在另一个平台上执行。

此外,可执行文件中仅包含在加载到内存后执行的一小部分代码。可执行文件链接到系统库,这些库提供了大部分功能,使程序能够与系统交互。
由于各个系统非常不同,因此库也不同,例如,为Linux编写的程序不能在FreeBSD上运行,尽管后者也使用ELF,因为它们未链接到相同的库。

要在Linux上编译Windows可执行文件,可以使用称为交叉编译的技术。 毕竟,编译器只是将代码编写到二进制文件中的程序,因此任何编译器理论上都可以为任何平台编写代码,只要目标系统的库可用于链接。

MinGW-w64项目提供了一个工具链,允许这样做。 例如,您可以使用sudo apt-get install mingw-w64命令在基于debian的系统上安装它。

安装后的可执行文件可以像这样使用:

i686-w64-mingw32-gcc hello.c -o hello32.exe      # 32-bit
x86_64-w64-mingw32-gcc hello.c -o hello64.exe    # 64-bit

请注意这并不是全部的问题:例如,OpenBSD和Linux都使用ELF作为它们的二进制文件格式,但你不能在OpenBSD上执行Linux的二进制文件。另一方面,借助于Wine,你可以在Linux上执行Windows二进制文件。 - fuz
@FUZxxl 说得好。我相信OpenBSD有一个compat_linux仿真层,允许Linux二进制文件在那里运行。 - SirDarius
2
我想要暗示的是,二进制格式与这个问题无关。真正的答案是,二进制文件试图与之交互的操作系统不同,除非有某种系统调用翻译层,否则无法运行该二进制文件。 - fuz

0

这是一个编译的情况,不同于Java的.exe没有任何虚拟机来解释代码在不同的操作系统上。因此,他需要具有所有特定的.dll和lib文件来执行为其设计的工作。

在.exe中,所有的东西都是为特定的操作系统而设计的,而在Java中,虚拟机是一个神奇的存在,可以解释和运行你的代码在不同的操作系统上。


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