百科问答小站 logo
百科问答小站 font logo



像C语言这样的编译型语言能否在不同CPU上,通过相同标准库的编译器,用源代码实现跨平台? 第1页

  

user avatar   haozhi-yang-41 网友的相关建议: 
      

理论上可以,实际上当然也能做到,但毫无现实意义。

原因有很多,例如说:设计一份兼顾性能、兼容性、通用性、扩展性的API的难度,远高于你的想象

对,我不管实现,光说设计,就已经很难了。最典型的例子莫过于GPU的API,光是成熟的已经有DirectX/OpenGL/Metal/Vulkan等几大套,每一套还有若干个前后向兼容性也不见得多好的大版本,有些还分桌面和移动(嵌入)版。

更何况,这套东西还要兼顾各软硬件厂商的各种小九九,各种勾心斗角。你真搞了这么个“标准委员会”,那你就等着天天吵架,10年出不了一个新版本吧。甚至哪怕是C/C++这样已经算是很成熟而且没太多直接利益纠葛,而且往往已经有业界现成通行标准的,你看看它们的效率啊:

posix的线程api在95年的POSIX 1c就已经定义了,而且很快就在*nix系统中成为实际标准。然而,线程进入C/C++标准里面是11年的C11/C++11,也就是过了16年时间。另外,读写锁这玩意在04年出现在pthread库里了,然而要等13年之后的C++17才进入C++标准,哪怕是动手比较快的boost,也是12年才有,那也过了8年了——至于C,没记错的话,到目前为止都只有C11的互斥锁(mtx_t)而没有读写锁。


至于什么图形库、并行计算库之类的,这甚至直接和很多厂商的收入密切相关的,那就更麻烦了。这种事就不是技术问题,而是利益问题和政治问题了。


甚至都不用说在业界这么复杂了。哪怕在一个大点的公司里,除了你自己弄的全新项目外,想动原有的API?那你就等着被各路人物各种理由狂轰滥炸吧。

那如果不动原有的,你的新功能新特性就只能往上堆,光是兼容性就够你折腾的,至于什么优雅的设计,早就顾不上了。更何况,这么玩的时间久了就成了屎山,这时候你还想招呼别人去按照你这屎山去实现?


user avatar   s.invalid 网友的相关建议: 
      

你说的其实是这个: en.wikipedia.org/wiki/P

The Portable Operating System Interface (POSIX) is a family of standards specified by the IEEE Computer Society for maintaining compatibility between operating systems. POSIX defines the application programming interface (API), along with command line shells and utility interfaces, for software compatibility with variants of Unix and other operating systems.

POSIX 是什么?让我们听听 Richard Stallman 的诠释 - 知乎 (zhihu.com)


事实上,如果所有操作系统都能满足POSIX标准的话,不光是C,任何编程语言都可以轻易在不同操作系统间移植。


注意POSIX只定义了API。这意味着不同系统间移植需要重新编译程序。

如果能统一ABI,那么只要程序编译出来、放到任何系统上就都能运行了。


问题是,哪怕仅仅统一API也是非常困难的;ABI就更不用提了,从CPU就不对味。


统一API的困难并不仅仅是政治上的。

技术上,不同内核、不同架构的操作系统是很难做出完全一样的API的。比如Windows搞了完成接口,Linux则走了epoll路线,两者的API自然南辕北辙。


山不来就我,那我就去就山。


这也有两个思路。


一是C风格的,典型如Qt。

这个思路是,我写一堆函数库,用这些库隐藏不同操作系统API的差异。

——得益于posix的推行,现在各大操作系统对posix都有相当程度的支持(但很难说“不错”);因此,不同OS之间,大量的API还是可以兼容的;哪怕不兼容,往往也只是风格上的些许差异(而不是思路上的根本区别)。这就为“隐藏API差异”这件事降低了难度。


比如,Windows和Linux的网络模型不同?

没关系,我搞一个站在中间的libevent。

对libevent来说,它能感知不同操作系统的差异、继而用宏之类手法在不同操作系统上选择不同的实现方案;但对libevent的用户来说,所有操作系统下,libevent的API都是一样的。


二是Java风格的

这个思路是,我写一个虚拟机,不光隐藏不同操作系的API差异,还要隐藏它们的ABI差异!


比如,不用管CPU是arm还是x86,你能看到的就是jvm;Java源码会编译成jvm上的字节码,丢给jvm“解释执行”。


这个“解释执行”也大有讲究。

正常的虚拟机,那是读一条机器指令执行一条;而jvm呢,它意识到——其实C、汇编也能解释执行!

事实上,Linux上,经常就会把一些语言先编译到C,然后再丢给C编译器继续编译到机器码。比如大名鼎鼎的c front就是这么做的。


换句话说,被解释执行的并不一定要是真正的机器指令:我完全可以站的更高一些,设计一套离高级语言更近、更容易分析其逻辑的指令集。

那么,第一步,把Java源码编译成统一的jvm字节码;第二步,用jvm“执行”这些字节码。


所谓“执行”,暗地里也可以是“编译”——jvm所在的操作系统是什么、CPU是什么,就针对性的编译过去;边编译边执行。

这就是所谓的JIT。


容易看出,jvm比c做的更彻底:C需要借助一些兼容性措施(或者第三方搞出来的、兼容多平台的库)隐藏不同OS的API差异,从而“一次编写,多次编译,到处运行”,只需下载对应平台的编译版本即可:

而jvm则做到了ABI兼容,一次编写,到处排错……哦不,到处运行——jvm会帮你即地编译。大概吧。


注意,你自己的山寨平台可未必有jvm。开发了一颗新的CPU或其它软硬件平台后,你需要自己移植一个jvm。你不移植jvm,你的平台可能就没有jvm用,自然也支持不了Java。

好消息是jvm并不难移植;坏消息是这个移植工作量并不小。


尤其是,源码到jvm字节码毕竟经过了一次转换。这次转换造成了很多信息的丢失,以至于不得不花心思把它找回来——比如所谓的“逃逸分析”。

好消息是,的确有很多信息可以找回来、尤其在(被迫)换了一种思路的前提下,反而能得到某种突破(典型如jit);坏消息是,信息丢了就是丢了,后找的怎么都不可能像原始信息一样清晰、全面。

更坏的消息是,这些高级技术实在难懂。因此,大量的小众平台上,你不可能找到效率比较过得去的jvm移植。


总之,C风格的“一次编写、多次编译”,无论程序的开发者还是使用者都更为麻烦一些:前者需要针对每个平台完成编译,后者需要知道自己平台的基本技术参数、这才能选中合适版本(比如说是arm还是x86、是32位还是64位、是Windows还是Linux还是OS X,等等);但它的执行效率有保障。


而Java风格的“一次编写,到处……咳咳,到处运行”呢,对开发者和使用者来说都非常方便,拿来都能用(哦,移动平台和PC/服务器经常还是要区分下的);但压力都放在jvm上了——如果jvm移植/实现的不够好,效率就……

不仅如此。由于前面提到的“转换到字节码产生的信息丢失问题”,Java程序的效率往往会有些缺陷——因此原本只支持Java的Android不得不开放了NDK,也就是采用了C风格移植方案。然后,为了弥补C风格方案用户必须知道哪个版本适合自己的弊端,又通过应用商店自动识别用户手机CPU、给他分发正确的应用版本。当然,google play之外的第三方应用商店未必有这个支持。


总之,跨平台是一个很重要的需求,业界一直在努力;只是牵扯到的东西实在太多,而且不同方向都有自己的问题(这些不同方向本身就引起了新的分歧),很难一蹴而就罢了。


user avatar   neoxiaoyi 网友的相关建议: 
      

语言本身就是跨平台的,不同平台不同编译而已。

之所以称Java这种语言“跨平台”是因为它用.class之后不需要额外的编译环节就可以在不同平台直接运行了,而C这类语言如果你拿到源码自然可以在几乎任意平台进行编译运行。


user avatar   pansz 网友的相关建议: 
      

题主如果读一下C语言的历史,就会知道C语言本来就是用来干这个事的。

C语言是为Unix设计,而Unix当初,就是各种小型机中型机大型机每个都有不同的cpu架构以及不同的操作系统(都是不同风格的不兼容的unix)。

所以C语言一开始就是被设计为源代码级跨平台的语言。为了解决如何在不同cpu不同操作系统中都能编译使用同一份代码。


user avatar   gou-rou-hua-yu-guo 网友的相关建议: 
      

可以,所以我们经常说写c语言要注意可移植性




  

相关话题

  请问#define PI 3.1416比float pi=3.1416有什么优势呢? 
  Linux 系统有没有关于 rm -rf /* 的保护机制? 
  编程那么难,为什么不弄一个大众一学就会的计算机语言呢? 
  计算机本科生花大量时间写编译器,操作系统是不是不务正业? 
  零基础如何自学编程? 
  如何看待萧井陌办IT培训班? 
  如何看待“郑大一附院”系统违规操作损失800万,肇事者被判五年半? 
  C语言指针难吗?如何看待数学大v认为指针比范畴论还难? 
  for(int i = 0; ; i++); printf("i love you"); 请问这条代码是什么意思,可以运行出什么结果? 
  汉字在计算机中的表示方式有哪些? 

前一个讨论
汽车有后置后驱吗?有什么优缺点?
下一个讨论
是否发现没有卫星而带有行星环的行星?





© 2024-11-21 - tinynew.org. All Rights Reserved.
© 2024-11-21 - tinynew.org. 保留所有权利