当前位置: 华文星空 > 知识

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

2020-04-11知识

@pansz 的说法里面有几个小问题

一个是java并不是自带编译器,而是jdk是一个比较完备的工具集合,全称是java development kit,所以理论上,你并不需要其他工具,有jdk,其实就什么都够用了,但真正下发生产的时候,我们并不会把javac之类的都一并发出去,一般就是 class文件,或者jar文件,或者做了aot之后的native image,一些二进制的启动文件,但本质上不会把编译器一起下发,所以自带编译器这个说法有点问题,java的编译器就是编译器,跟其他语言的编译器没有什么不一样,jdk你也要去下载,如果操作系统不带c编译器,也没带java编译器

第二个是自举,openjdk现在主流的开发语言的确是c++,hotspot是c++在编写,但是随着graal圣杯项目的出现,java已经实现了自举,graal是符合jdk标准的编译器,跟openjdk一样,而且理论上并不依赖c去实现编译器,理论上你可以用任何一个图灵完备的语言,实现java的编译器,这里面说的依赖c去实现java的跨平台特性,那从graal诞生之后起,其实可以不这么认为, c并非必需

然后我们正面回答问题

为什么说c,c++不能跨平台,这里说的不能跨平台,意思是,不能实现: 一次编译,到处运行

java可以,当然java到处运行时候,人家让不让你运行那就是另外一回事了,比如app store就不让你随便这样搞,要求你编译成native,二进制机器码

举个例子,比如c写了一段代码,我想在mac上编译,在win上运行,可以不可以嘛?

不行吧

当然说可以用交叉编译,那我认为交叉编译才是跨平台,而不是你缺省的这个编译器,这里就引入了一个新的概念,交叉编译

但是java我可以做到一次编译,到处运行,而实际上我们就是这么干的

实现在win,mac还有linux上做好runtime,然后每次更新的时候,就不需要更新runtime,只更新 class或者jar文件,这样就实现了一次编译,到处运行

只要不同的平台上有对应的运行时,就可以运行我想让它运行的代码,而不需要重新编译

用这种手段,我就做到了在mac上开发,然后发布的时候,发布到win,mac和linux三个平台上去

c就做不到这一点,当然你可以说交叉编译,那其实等你真的操作下去,你就会发现,不同平台上的api都他么不一样,格式不一样那都是小意思,api各种不一样,然后你就改来改去,封装来封装去,大量的资源和精力浪费在这种你觉得不重要的事情上,对我这种懒惰的人来说,非常不友好

java为什么当初会流行?就是因为程序员们烦透了在不同操作系统上编译来编译去,而且c/c++编译很慢,编译成native没有几个快的,一个大项目一不小心编译一个多小时很正常,openjdk是c++写的,你知道编译要多久吗?一次2个多小时,那这种编译的速度,每次都在这边等等等,谁吃得消?

当然你可以说hello world编译很快,但是问题是工作中写的都是hello world?

相比之下,java编译几乎是最快的,编译到字节码已经很快了,而且编译次数也不用每次都去不同平台上编译一遍,这样就快很多,开发起来就有效率

用流行一点的话说就是, java可以同时实现aot和jit,c只能aot,不能jit ,不考虑特殊小众情况

这里也没有必要故意混淆什么c的跨平台,我想大多数人认知的跨平台,就是java的那种跨平台,而不是各种自定义的跨平台,这里没有必要抠字眼

当然你说c比汇编什么更跨平台,那是

但是我想一般人说的跨平台不是这种程度上的跨平台,毕竟现在是2021年,不是1991年

实际工作中,如果你只在源码层面跨平台,那工作量可多了不止一倍,比如我想弄一个动态库,要面向三个平台,那么你要同时编译成mac的dylib,win的dll和linux的so文件,淦,累死,java只要一个jar,搞定,而且java编译还快,c++的编译还慢

另外你也会担心java的源码可以被反编译

我的心得,用groovy当java写,反编译出来的源码自带混淆,我们实际工作中发生过的案例,有同行用kotlin写,被人反编译了,结果发现,淦,看不懂,遂作罢。所以如果你真的担心被反编译的话,除了编译成native image也就是aot以外,你也可以混入其他jvm的语言,比如kotlin,groovy,clojure什么都可以,反编译出来的,一般人看不懂,尤其是groovy,你可以把groovy当java写,而且groovy反编译出来的源码就跟你手写的java源码不一样,破解起来难度要高很多

现在同时支持aot和jit的应该是主流了,dart,swift什么都在朝着这个方向前进,java也不例外,c和c++其实应用面会受限,做起来太慢了,尤其是c++,现在我越来越觉得c++以后可能只是给java开发类库一样的存在,项目中不会大量使用c++,你看flutter/dart,swift那边,也都是这种情况,c++开发类库可以,但是一般用户不会用c++做项目

关于java调用c/c++的api,类库这些,java有一个项目叫做panama,最近一堆人在跟他们闹呢,因为panama又开始incubator了,然后一堆人闹,怎么又开始incubator了,太墨迹了,然后官方说

等panama成熟,然后graal再成熟一点,以后应用面你用c或c++主要就是写类库了,常见的类库就是图形相关,比如javafx,flutter,都有相当一部分的c或c++代码,用来封装metal,opengl,directx之类的api

稍微进化一点,像2d游戏引擎什么,已经全部用java,kotlin [1] ,dart [2] 这种级别的语言实现了,3d还需要时间,但是我相信,迟早的事

参考

  1. ^https://github.com/AlmasB/FXGL
  2. ^https://flame-engine.org/