使用c / c ++编译器为OS(比如linux)和没有OS(比如嵌入式DSP目标)编译时,两个空程序main {}
有什么区别?我特别想知道当存在操作系统时编译器的作用会有所不同。两种情况下编译器/语言运行时有何不同?
答案 0 :(得分:12)
实际上,链接器在打包程序以在操作系统上运行时执行不同的工作,而不是构建仅在裸硬件上运行的程序。编译器只生成包含针对主机体系结构的指令的目标文件,这些块稍后由链接器组合和打包。
要在操作系统上运行的程序必须具有某种二进制结构 - 这是可执行格式发挥作用的地方。例如,这种格式可能要求程序在开头应该有几个标题部分,然后代码应该跟随。操作系统加载程序的工作是解释此结构,然后向CPU提供代码部分包含的指令流。
相比之下,一个打算在裸硬件上运行的程序通常没有特殊的结构,可以直接送到CPU。
答案 1 :(得分:6)
实际上,链接器在打包时执行不同的工作 程序在操作系统上运行而不是构建程序 仅在裸硬件上运行。编译器只生成对象 包含针对主机架构的指令的文件, 这些块稍后由链接器组合和打包。
要在操作系统上运行的程序必须具有 某种二进制结构 - 这是可执行格式的用武之地 玩。这种格式可能要求该程序应该有一些 在开头的标题部分,然后代码应该遵循,为 例。 OS加载程序的工作是解释此结构 然后用代码流指令提供CPU 部分包含。
相比之下,一个旨在在裸硬件上运行的程序 通常没有特殊的结构,可以直接喂养 CPU。
我想借助布拉戈维斯特写得非常好的答案。事实上,他建议可执行容器格式和二进制接口之间存在差异等等。但是,最大的区别可能是实际执行应用程序代码的主要入口点,以及启动代码和运行时库的存在;但是,如果你知道你正在做什么,你也可以避免在完整的操作系统上与后者联系。
通常,如果存在启动例程,运行时库(例如crt0),则应用程序的实际入口点不是main
,而是其他内容(通常为_start
)。在此实际入口点之前将控制权移交给main
,它可能会执行一系列非常具体的任务,通常与初始化有关。
more information on crt0总是有维基百科。
但是,在裸机平台上可能没有与编译器捆绑在一起的例程。因此,控件可能会直接发送到您的main
,并且在平台上执行的第一个代码将是您的。
你去了,这是两种main
之间最基本的区别。但是,我不得不说你的问题有点模糊,因为你可以在没有启动脚本的情况下解决,如果你自己初始化堆栈等,你也可以使用运行时库来完成所有这些(大多数?)裸 - 金属平台。实际上,这完全取决于您的编译器套件,您要定位的平台等等。
答案 2 :(得分:3)
我很想说没有区别。什么编译器 (或翻译系统)在很大程度上是实施 依赖;翻译系统可能会做不同的事情 对于Windows而不是Linux,即使它们都有资格作为操作系统。
主要区别在于实施是托管还是托管
不。如果它没有托管,那么它甚至可能不支持
main
,如果是,则可能不支持main
参数。非托管实现的功能或要求
for startup是实现定义的。虽然还有一个
很多关于启动的“实施定义”
托管环境,实现 需要支持
main
,返回int
并且至少有两个签名,以及
应用程序需要提供这样的功能。
请注意,在过去和今天,许多实现都是如此
你会想到托管真的不是出于各种原因。
例如,在过去,g ++将自己记录为非托管
(至少gcc确实如此),因为他们无法控制,也无法控制
保证库的部分实现。乃至
今天,微软的C ++只能被认为是托管的时候
生成控制台应用; Windows应用程序没有
有一个main
。
答案 3 :(得分:0)
@BlagovestBuyukliev提供了一个写得很好的答案。
我想稍微扩展它 - 没有操作系统实际上意味着没有软件实现的操作系统。能够执行二进制代码的硬件还具有处理程序加载并将其提供给CPU以及所有其余低级细节的协议。在这种情况下,“OS”实际上作为HW实现的存在。从这一点来看,它与标准操作系统之间的差异不是主要的,而是技术性的,就二进制代码执行而言。