java分析c代码-java 调用c 代码
如果想让程序员之间吵起来,怎么办呢?
很简单,你只需要大喊一声:”PHP是最好的语言!“
但是感觉网上那些语言争论和鄙视链完全没必要,做底层的看不起应用层的,做后台的看不起前端,做算法的看不起纯开发......
其实没有一种编程语言能胜任所有领域,软件开发也没银弹。
比如操作系统、数据库、Web 服务器、驱动、高频交易、游戏、搜索引擎等场景则是 C/C++ 更加适合。
而机器学习、数据分析、爬虫等则 Python 更加适合。
后台业务开发、大数据开发等则是 Java、Go 、PHP等语言的天下。
前端开发则是 JavaScript 。
从 TIOBE 编程语言榜单可以看到,C、Python、Java、C++ 基本上是稳居前四名,尤其是 C ,作为偏底层的语言还能常年稳居前三,可见其影响力:
我们可以对不同的编程语言进行不同维度的分类,比如通过执行方式来划分:
我们可以分为:
1、汇编执行型
这种方式一般指汇编语言,汇编语言(assembly)的源文件由汇编器(assembler)转换为 CPU 可直接执行的二进制程序文件,并且多个二进制文件通过链接器(linker),链接为一个二进制程序。
当然,现在大多数人可能都不会再学习汇编了,这玩意吃力不讨好,但是我还是建议有时间的话可以学一下汇编。
倒不是说汇编多底层多多牛逼,主要是汇编其实是离计算机最近的一种语言,学汇编有助于让我们理解计算机执行的方式,比如各种指令其实就是对应计算机在存储、计算的特征。
另外就是,不管 C/C++ 还是 Java 等语言,出问题了可能都要单步调试,就算是 Java 这种虚拟机型的语言也有类似汇编的指令集,遇到程序崩溃的时候也许查看汇编代码,一步步 debug 汇编是你唯一的选择。
2、编译汇编执行型
对于现在很多高级语言来说是这种方式,比如 C、C++、Go、Rust 等。
他们的源文件一般由编译器(compiler)先编译为汇编指令,再由汇编器生成 CPU 可直接执行的二进制程序文件。
当然我们有时候也将编译、汇编整个过程合并说为:编译。
但是一般这里的编译又分为前端和后端,前端是指通过语法分析、语义分析生成中间代码的过程。
语法分析就是解析 Token(符号)并且建立抽象语法树(AST) 的过程,本质上编程语言执行过程,就是遍历这颗语法树的过程。
比如对于这段代码:
var a = 42;
var b = 5;
function addA(d) {
return a + d;
}
var c = addA(2) + b;
生成的语法树如下:
当然了,现在编译器不特殊指定的情况下,一般不会把编译出来的汇编指令输出到文件,在内存中直接交给内置的汇编器进行处理,所以我们会看到这些编程语言的编译器直接就输出一个可执行的程序文件。
比如
gcc hello.c
就会直接输出 a.out 可执行文件,但是如果你想看到编译、汇编这个过程的话,可以这样:
gcc -s hello.c -o hello.s
它会在当前目录生成 hello.s 汇编文件,
汇编过程则将上一步的汇编代码转换成机器码,这一步产生的文件叫做目标文件,是二进制格式。
编译的命令为:
gcc -c hello.s -o hello.o
接下来我们还需要链接才能成为可执行文件,链接过程使用链接器将该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。
附加的目标文件包括静态连接库和动态连接库,包括我们常见的 stdlib、stdio 等库。
链接过程的命令为:
gcc hello.o -o hello
基于 AST 我们甚至可以做到语言间转化,也就是从一门编程语言转化为另外一门语言。
3.编译解释执行型
这种对于 Java、Scala 等编译型虚拟机语言比较常见,通常是由 Java 编译器编译为 class 文件(字节码文件),我们可以把 class 文件和 C 语言编译后的二进制格式文件类比,只不过各自语法不同罢了。
class 文件由 Java 虚拟机(Java virtual machine ,简称 JVM)解释执行。
C#、VB 等语言则由其编译器编译为二进制的 exe 或 dll(动态链接库) 文件,由 .net 运行时(runtime)程序解释执行。
显然这类语言没有编译汇编型高效,因为需要去解释执行,这个过程是逐条翻译、效率相对低下。
但是 JVM 为了解决这个问题引入了 JIT(Just In Time),简单来说就是:
首先我们的 Java 代码由 javac 等编译器 编译为JVM 可执行的字节码(ByteCode),然后JVM 会判断这段代码是否为热点代码,如果是那么使用 JIT 技术,如果不是那么解释执行,最后变成机器码,由操作系统分配然后 CPU 具体执行:
4. 解释执行型
解释执行型语言通常又被称为脚本(script)语言。
典型的比如 shell、Powershell、JavaScript、Python、PHP、Ruby 等。
它们的源文件由相应的运行时程序直接读取并解释执行。
当然了java分析c代码,到底是编译执行还是解释执行其实不是编程语言本身的特点,比如你要是愿意也可以写个解释器去解释执行 C 语言。
也可以写个编译器去编译脚本语言,比如谷歌的 V8 执行 JS 高效的一个重要原因就是会类似 JVM 一样,对热点代码进行标记为HotSpot,然后将其编译为更高效的机器码,下次执行到的时候直接使用机器码代替字节码执行。
5、编译转换、解释执行型语言
这种其实和上面几种差别不大,就是多了一个编译转化的过程,比如 TypeScript、JSX、CoffeeScript 等语言通常是先由编译转换程序转换为 JavaScript,再由 JavaScript 运行时解释执行。
因为浏览器引擎、NodeJS 等环境只能执行 JavaScript,所以 TS、CS 等语言就只能先通过编译器转化为 JS。
现在有很多成熟的工具都能提供这样的能力,可以去试下,比如将源语言先编译为 AST,将语法树输出为 XML 格式,再转化为 目标语言。
已经有可用的了,GCC-XML:
6、执行效率
很显然,编译得越彻底的语言执行起来越高效,比如 C、C++ 这类都是直接编译为了二进制,是 CPU 可以直接识别、执行的指令。
而 Java 则是编译为 class 格式文件,由虚拟机在运行时将其转化为不同平台上的 CPU 指令执行,不需要再对源代码进行语法分析、词法分析等过程,会比解释执行型的脚本效率要高很多。
但是编译、解释执行型语言在执行时又比汇编 / 编译执行型语言多一个将虚拟机指令转换为 CPU 指令的过程,所以它们运行效率通常又比汇编 / 编译执行型语言的低。
因此,在对执行效率要求高的场景(例如高频交易、数据库、搜索引擎)java分析c代码,通常不采用解释执行型语言,而是采用编译执行型语言来开发。
尤其是高频交易,它们为了提升一点点延时,做了极致的优化,甚至会尽可能的利用编译器完成计算(C++模板元编程):
尽量避免系统调用(例如做内核旁路);
2)尽量避免运行时动态内存分配;
3)会自己做超低延时的通讯协议;
4)会做大量的 benchmark以及特定场景的优化;
5)会尽量在编译期解决问题(模板元编程),少用多态;
7、系统级编程语言
我个人对系统编程比较感兴趣,而以前系统编程基本上就是 C/C++ 编程,所有的系统级软件几乎毫无例外都是 C/C++ 编写。
因为编译解释型语言或者脚本语言的运行效率不如编译执行型语言,而且需要虚拟机或者解释器才能运行,因此在操作系统或者驱动程序的编程中通常使用的是编译执行型的语言。
前两天我推荐了一门系统语言:Rust。
因为 Rust 优点很多,比如 足够底层、极高的内存利用率、高性能、可靠性,Rust 本身设计机制和所有权模型就能保证内存安全和线程安全,尽可能把错误在编译期暴露出来了。
总的来说,Rust 是一门可靠的系统编程语言,拥有 C++ 一样的高性能、底层和抽象层次,但是又比 C++ 安全。
在系统编程之下就是更加底层的场景,比如和 CPU 架构密切相关的地方,例如操作系统的内存管理模块的设置页表地址的程序,或者需要使用 CPU 的 IO / 中断等指令的时候,基本上只能使用汇编语言。
或者是 C 语言 + 内联汇编等。
8、到底学什么语言呢?
说了这么多,那么到底学什么语言呢?
说实话当你入门之后,我觉得这个问题就不是问题了,因为你需要用到什么语言就去学什么,而且基本上都会很快学会。
但是入门的话, Python、C 都可以,如果是非科班的我觉得先学 Python 比较好,Python上手快、简单一些,先用 Python 养成编程思维、喜欢上编程,再去学其它的。
当然科班的依然可以先学 Python,并且国外不少高校第一门语言现在比较喜欢教 Python、Schema 这类。
但是我个人更建议科班大一的同学可以先学 C,先把难啃的啃下来,之后学其它语言就很快了。
入门之后,我个人建议的配置是:
1-2 门编译执行型 + 1-2 门解释执行型 + 1 门函数式编程语言。
比如 C/C++ + Python + Haskell
或者 Java + Python、Shell + Haskell、Erlang 等
这样可以让我们学习掌握多种编程范式,尤其是函数式编程语言,和我们常规的编程思维截然不同。
好了,这期就到这里吧,下期我们再来从其它维度来看编程语言,以及各种编程语言的适合领域和就业前景~