这个问题一直困扰着我一段时间。让我们考虑以下两个程序:
#incude <iostream>
int main()
{
std::cout << "Hello, World!";
}
和
int main()
{
int x = 5;
int y = x*x;
}
我知道这取决于编译器和操作系统,但我需要一般性答案或特定示例。 TIA。
答案 0 :(得分:7)
作为一般答案,第一个将需要C ++运行时库(支持标准库调用所需的东西)。这些构成了语言和支持库之间的各种接口,后者又知道如何在给定环境中实现它们的功能。
第二个不使用运行时库。它将使用C启动和终止代码(初始化和拆除C环境),但它是关于这些是否被视为运行时库的一部分的讨论点。如果你认为它们是一个部分,那么,是的,它们将被使用。它可能是一个非常小部分,因为启动代码和流内容之间的大小通常有很大差异。
您可以静态链接代码(在链接时绑定)与运行时库或动态链接(以便在加载时完成实际绑定)。这对Windows和Linux都是如此。
答案 1 :(得分:7)
对于Windows应用程序,您可以使用 Dependency Walker 查看所有依赖项。
答案 2 :(得分:2)
第一个程序执行流I / O,这意味着它必须与OS管理的资源(console,gui)进行交互。因此,最终,必须通过系统DLL中实现的API调用操作系统。
在Windows上,第二个程序不需要库。我很确定在Linux上也是如此。
答案 3 :(得分:2)
使用GCC编译它们,并在控制台写入中获取名为“hi”的可执行文件:
ldd hi
将为您提供连接到您的程序的共享对象(动态库)。
这里只是为了快速回答输出:
ldd tifftest
libtiff.so.3 => /usr/lib/libtiff.so.3 (0x4001d000)
libc.so.6 => /lib/libc.so.6 (0x40060000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x40155000)
libz.so.1 => /usr/lib/libz.so.1 (0x40174000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
答案 4 :(得分:2)
好吧,让我们从更一般的角度来看待这个问题:
首先,您需要一台具有兼容CPU 的计算机,该计算机可与编译器输出的目标计算机配合使用。您可能认为这是显而易见的,但假设代码编译为x86机器代码,它将不会在使用不同指令的Alpha CPU上运行。或者,如果编译为x64机器代码,则它不会在仅限x86的CPU上运行。因此,运行C ++程序需要正确的硬件,这与基于虚拟机的语言(如Java)相反,后者将其抽象化。
您还需要正确的操作系统。我不是移植程序的专家,但我认为不可能在C ++中构建一个在多个操作系统上运行的可执行文件。例如,即使你的第二个例子编译到Windows,在实际调用main()
函数之前和之后的幕后都会有大量的运行时库代码。这将执行诸如准备堆和初始化CRT库之类的操作。 Windows的CRT是通过Windows API实现的。您可以静态链接库,因此不需要CRT DLL,但程序中的代码仍然会调用Windows API,因此仍然依赖于平台。作为一个实验,我在Windows上用Visual Studio编译了一个静态链接的空程序,根据Dependency Walker,它仍然引用了KERNEL32.DLL来处理像HeapCreate
和ExitProcess
这样的函数。因此,“空”程序仍会为您做一大堆操作系统,准备做一些有用的事情(无论您的程序是否有用)。
另请注意,可能存在最低操作系统版本:由于调用EncodePointer
和DecodePointer
,Visual Studio 2010甚至需要Windows XP SP2或更高版本的空程序。请参阅this question。
系统必须具有内存才能启动您的程序。您可能认为它什么都不做,但如上所示,在调用main()
之前,整个OS加载初始化调用是由程序库完成的。这些可能需要一些内存,以及执行它所需的处理时间。
根据操作系统的配置,您可能需要足够的安全权限才能启动可执行程序。
因此,简而言之,即使使用静态链接运行空C ++程序,您也需要正确的CPU,操作系统,运行可执行文件的权限以及完成程序的内存/处理时间。与Java或.NET等VM技术相比,这些要求可能只会减少到正确的虚拟机,必要的权限以及运行程序所需的内存/ CPU时间。这可能不像听起来那么简单:您可能需要虚拟机的正确版本,例如.NET framework 4.0。这会使您的分发过程复杂化,因为为机器更新整个JVM或.NET框架可能是一个耗时的过程,需要管理员权限和Internet连接。在一些狭隘的情况下,这可能是一个交易破坏者,因为在极少数情况下,它可能更容易说“它将在任何x86兼容的Windows操作系统上运行自XP”,而不是“任何具有最新虚拟机的机器昨天才发布的机器“。但是,对于大多数用途,虚拟机允许您(理论上)忘记CPU和操作系统这一事实使得程序的分发更容易;使用C ++,您需要至少为要支持的平台和CPU的每个组合编译单独的可执行文件,而不管您正在使用的库的其他要求。
答案 5 :(得分:1)
Windows上的C程序需要Windows附带的CRT库。 C ++有时需要所谓的“C ++可再发行”。它们可以通过链接嵌入到应用程序中,但这会使EXE更大。
答案 6 :(得分:1)
对于问题的第1部分 - 您已被几位成员回答。 但我所说的是一般的,并且两种情况都需要 - (如果你不知道的话)
对于任何要运行的程序,必须为其提供所需的资源。回答第一部分团队已经列出了几个项目。
但总的来说,它需要的是明确定义的地址空间(在主存储器中),其属性和CPU时间。操作系统可确保您在执行程序时获得该功能。除非有一些荒谬的冲突,否则你的程序会得到这个(这就是为什么我猜Chubsdad评论“你需要运气”)。
操作系统调度,CPU要求从内存中获取指令/数据然后执行它...所有这些都构成了执行程序的“机器”。
查找入口点(或程序中要执行的第一个点)是在编译时(例如主函数)或使用某些系统调用(如exec)加载程序时(在Unix中)决定的所有内容/ CreateProcess()(在windows中)。
答案 7 :(得分:1)
在Linux上,任何C程序都静态链接到某些CRT库。该程序的真正入口点是/usr/lib/crt1.o中定义的_start()
函数。此函数调用一些libc函数,如__libc_start_main()
。因此,您仍然需要libc库...
你可以不用libc,但这很棘手。您需要重命名输入点_start()
,或指示链接器从main()
开始。并且你还需要一些内联汇编来在程序完成时发出_exit()
系统调用,否则它就会崩溃。当然,使用ld
命令显式链接,而不是通过gcc
前端。