为什么说c,c++不能跨平台,编译器是在计算机操作系统上的吗,难道说编译器不在c,c++程序里吗?

曾传新


c语言编译是把c源码翻译成计算机可以识别的二进制机器码的过程,编译器相当于翻译器,所有的程序如果要执行都是通过操作系统执行对应的机器码的,不同的系统执行方式是不同的,所以要在不同系统中运行程序,源代码一般不需要重写,但是需要重新翻译成新的系统可以识别的格式,所以需要使用对应系统的编译器重新进行编译。像JAVA这种号称跨平台的语言实际上是依靠在JAVA虚拟机上执行编译后的文件做到的,把源码编译成所有系统的虚拟机都可以执行的文件,但是运行虚拟机会有一定的性能开销。类型js或Python这类解释型语言需要在解释器上直接执行的,其实和JAVA虚拟机类似,只是没有了编译这一步,源码可以直接运行在解释器中,相对应的执行速度也会更慢一点


超神时代0


首先我们纠正一下题目中一个小小的误区,不是C和C++不能跨平台,应该是说是C/C++源代码在编译后生成的

.exe

文件不能跨平台,源代码和可执行文件要区分开来。

想要搞明白这个问题,我们先得了解一下源代码是怎么变成程序的。

四个过程:预处理——编译——汇编——可执行文件

当我们编写完代码后,源代码会经过上述的四个环节,最终变成常见的可执行文件。

  1. 预处理阶段(hello.i):在源代码中会有头文件,一些宏,注释等。预处理的目的就是将头文件展开,宏文件代换,去掉注释等,对代码进行一些初步的处理

  2. 编译阶段(hello.s):这一阶段主要是检查语法上的错误,比如内存有没有溢出,指针有没有指错对象,然后生成可汇编文件。

  3. 汇编阶段(hello.o):计算机是不认识代码的,所以需要将汇编代码转换成0和1组成的机器码

  4. 链接(a.out):链接有两种情况:静态和动态。静态库和应用程序编译在一起,在任何情况下都能运行;而动态库是动态链接,文件生效时才会调用。最终生成一个可执行文件。

编译器的作用

我们不要把编译器想的太厉害,觉得编译器是万能的。实际上编译器就像是一个翻译,负责把高级语言转变成机器能看懂的低级语言,翻译过程就是上述的四个过程。但是其中有一点需要格外注意。那就是不同的公司使用的指令集不同。输出程序的格式和CPU使用的指令集有关,比如X86,arm,还有MIPS等等, 由于设计思路的差异,所以不同平台上编译生成后的可执行文件格式是不一样的,可能在ubantu里能运行的C程序,放到windows下就会报错。

类比一下java,为什么说java可以跨平台,是因为java内置了一个虚拟机,程序都从虚拟机中跑的,所以有人说“java不仅是一种语言,更是一个平台”。


综上所述,C/C++的一些基础性代码是可以跨平台的(可能会受API影响),是生成的可执行文件不能跨平台,C/C++不自带编译器,不同平台下的编译器存在差异。

(都看到最后了,麻烦点个赞和关注吧,谢谢~)


爱思考的奥特曼


先来讨论一下C&C++语言的执行过程,从而搞清楚为什么C&C++语言不能跨平台。

我们分阶段来讨论(如图4所示):

  • 预处理阶段。预处理器(cpp)来把 代码中开头的行进行展开, 比如头文件,宏等内容,修改最初的C文件。
  • 编译阶段。编译器(ccl)将修改后的C文件,翻译成了 另一文本文件,,这就是我们所说的汇编程序了。

  • 汇编阶段。汇编器(as)将翻译成机器语言指令。 把这些命令打包成一种叫做可重定位目标程序(relocatable object program)的格式,此时的输出格式就是了。这其实就是二进制文件了。
  • 链接阶段。编译过程最后还有一个链接阶段(程序调用了 函数),最后的输出结果还是和上一步类似,都是直接二进制文件。
图2以上就是大家都知道的程序。最终执行的结果 就是在console上输出一行字符串, ,如图3,4所示,大家可以很清楚的看到X86和ARM不同的编译结果。而在他们输入的0和1中,有些代表的是指令,这些是有固定含义和编码的。也是芯片能识别的。而另一些是数据。这些不同的程序的数据自然是不同的。我们前面就说,不管多么复杂的计算机操作,到了cpu级别都是0和1,数据虽然多变,但是 指令的数量是有限的。因为 指令是要被芯片固定识别的。芯片中要用 晶体管(最初是电子管)组成的与或非门组合来识别这些指令和数据。因为直接输入0和1,实在太繁琐了,所以他们就发明了汇编语言。来简化 程序的编写。

比如 计算 1+1,两个 数据1都 使用 来表示,而 加操作,放在cpu中,可以是 (这个是胡乱写的),这个二进制代表的加操作能被计算机识别。而因为这个加操作对于cpu来说,编码的格式是固定的。所以可以直接一个助记符来表示,这样科学家们写程序就方便多了,而这就是汇编程序的由来。因为汇编程序完成之后,可以再有一个专门的程序(就是要上文中所说的汇编器)来把编写的汇编程序编译成0和1.这样计算机也可以识别了,而汇编语言本身也方便了程序的编写和阅读。

编写汇编比直接编写二进制方便高效了太多。但是 随着计算任务的复杂,程序的规模越来越庞大,使用汇编程序也很累啊,那么是否有更简单的方式呢?所以科学家们发明了高级语言(比如 ,等),在编写程序的时候,使用C语言等编写,然后再使用 编译器将C语言程序翻译成汇编程序,汇编程序再使用汇编器编译成0和1,这样,cpu能识别的东西没有变化,但是对于编写程序的人,确实方便了很多。

通过以上的描述,我们就知道了高级语言的大概由来。也明白了我们所编写的各种高级语言,到了最后,其实都是转化为二进制执行。

而直接二进制格式的程序,我们称之为本地机器码(native code)。而类似那些 之类的 助记符,以及汇编的编写格式或标准,我们称之为 指令集

但是问题的关键来了。不同公司所生产的 cpu芯片。他们所使用的指令集不同啊, 这种芯片设计的事情,没有国际统一的标准,甚至像intel所代表的复杂指令集,和arm为代表的精简指令集,还有PowerPC、MIPS等指令集,它们指令集的设计思路就是不一样的。

所以为什么说C&C++语言不能实现跨平台运行,就是因为它编译出来 输出文件的格式,只适用于某种特定的CPU,而其他CPU不认识啊。


分享到:


相關文章: