有和没有操作系统的两个空main{}程序有什么区别?

What is the difference between two empty main{} programs with and without OS?

本文关键字:main 程序 区别 什么 操作系统 两个      更新时间:2023-10-16

两个空程序main {}在使用带有操作系统(例如linux)和没有操作系统(例如嵌入式DSP目标)的c/c++编译器编译时的区别是什么?我特别感兴趣的是,当有操作系统时,编译器做了什么不同的事情。在两种情况下,编译器/语言运行时是如何不同的?

实际上是链接器在打包程序以在操作系统上运行与构建仅在裸硬件上运行的程序时执行不同的工作。编译器仅仅生成目标文件,这些目标文件由针对宿主体系结构的指令组成,这些指令块稍后由链接器组合和打包。

要在操作系统上运行的程序必须具有一定的二进制结构——这就是可执行格式发挥作用的地方。这样的格式可能会规定程序应该在开头有几个头节,然后代码应该紧随其后,例如。操作系统加载器的工作是解释这个结构,然后将代码段包含的指令流提供给CPU。

相反,在裸硬件上运行的程序通常没有特殊的结构,可以直接提供给CPU。

它实际上是在打包a时做不同工作的链接器程序在操作系统上运行与构建一个程序仅在裸硬件上运行。编译器只产生对象包含针对主机体系结构的指令的文件,这些块稍后由链接器组合和打包。

要在操作系统上运行的程序必须有特定的二进制结构——这就是可执行格式出现的地方玩了。这种格式可能规定程序应该有几个头段在开头,然后代码应该在后面,for的例子。解释这个结构是操作系统加载程序的工作然后给CPU提供指令流,让代码执行部分包含.

与之相反的是,在裸机硬件上运行的程序通常没有特殊的结构,可以直接馈送到CPU。

我想以Blagovest写得很好的答案为基础。事实上,正如他所说的,可执行容器格式和二进制接口之类的东西是有区别的。然而,可能最大的区别是实际的主入口点执行应用程序代码,以及启动代码和运行时库的存在;不过,如果你知道你在做什么,你也可以避免在一个成熟的操作系统上链接到后者。

如果存在启动例程,运行时库,如crt0,应用程序的实际入口点不是main,而是其他点(通常是_start)。在这个实际入口点将控制权交给main之前,它可能会执行一些非常具体的任务,通常与初始化有关。

维基百科上有关于crt0的更多信息。

然而,在裸机平台上,编译器可能没有绑定这样的例程。因此,控制可能会直接传递给您的main,并且在平台上执行的第一个代码将是您的。

好了,这就是两种main之间最根本的区别。然而,我不得不说你的问题有点模糊,因为如果你自己初始化堆栈等,你可以不使用启动脚本,你也可以在一些(大多数?)裸机平台上使用运行时库来完成所有这些。事实上,这完全取决于你的编译器套件,你的目标平台,等等。

我想说没有区别。多么了不起的编译器(或翻译系统)所做的主要是实现依赖的;一个翻译系统可能会做不同的事情,而不是Linux,尽管两者都是操作系统。

主要区别在于实现是托管的还是不是。如果它不是托管的,那么它甚至可能不支持如果支持main,则可能不支持main参数。非托管实现做什么或需要什么For startup是实现定义的。虽然也有一个很多"实现定义"关于启动在a托管环境下,实现所必需的main,返回int并且至少有两个签名,并且应用程序需要提供这样的功能。

注意,在过去和现在,许多实现由于各种原因,你可能会认为是托管的。例如,在过去,g++将自己记录为非宿主的(至少GCC做到了)因为他们无法控制,也无法控制保证实现的库部分。甚至今天,微软的c++只能被认为是托管的,当生成控制台应用程序;Windows应用程序则不然有一个main .

@BlagovestBuyukliev提供了一个写得很好的答案。

我想稍微扩展一下——没有操作系统实际上意味着没有软件实现的操作系统。能够执行二进制代码的硬件还具有处理程序加载并将其馈送到CPU和所有其他低级细节的协议。在这种情况下,"操作系统"实际上是作为HW实现的操作系统出现的。从这一点来看,它与标准操作系统之间的差异不是主要的,而是技术上的,就二进制代码执行而言。