python是脚本语言、需要编译器编译执行_从C语言编译看高级程序语言执行

从C语言编译看高级程序语言执行

1. C语言编译过程

编译过程流程图:

FOwn2W8n44JxV4NAYtZt2N9Y9IW8bf8YRXQpc6oER5BuzmPFBOVtc9bPgYkrfQY6ZT7ZkDEtQsu5K4Fsg8S9jdeAnbuABYK3YX0_rCSxCiJMdO3EO-ag6Nl8QOdaAcLUfRq8fdjyTIp6VXEkxEmW4F-Nih4dukUll_zHCxBltzu0

1.1. 预处理文本(Preprocessing)

解析源码文件文件中的宏指令,将源码转换为更详细的源码,对于文件main.c:

#include

int main(){

return 0 ;

}

定义main.h:

int add(int a, int b);

进行预处理:

gcc -E -I . main.c

参数-E含义:

-E Only run the preprocessor

参数-I含义:

-IAdd directory to include search path

输出结果内容:

# 1 "main.c"

# 1 "" 1

# 1 "" 3

# 361 "" 3

# 1 "" 1

# 1 "" 2

# 1 "main.c" 2

# 1 "./main.h" 1

int add(int a, int b);

# 2 "main.c" 2

int main(){

return 0 ;

}

预处理后的内容把#include替换成了main.h中的代码。

1.2. 编译成汇编(Assemble)

将预处理后的文件编译成汇编文件:

gcc -I . -S main.c

生成文件main.s:

.section__TEXT,__text,regular,pure_instructions

.macosx_version_min 10, 13

.globl_main ## -- Begin function main

.p2align4, 0x90

_main: ## @main

.cfi_startproc

## %bb.0:

pushq%rbp

.cfi_def_cfa_offset 16

.cfi_offset %rbp, -16

movq%rsp, %rbp

.cfi_def_cfa_register %rbp

xorl%eax, %eax

movl$0, -4(%rbp)

popq%rbp

retq

.cfi_endproc

## -- End function

.subsections_via_symbols

参数 -S:

-S Only run preprocess and compilation steps

1.3. 生成目标文件

目标文件也是机器码,但是没有运行库,不能执行:

gcc -c main.s -o main.o

文件内容main.o:

����� 8p�p__text__TEXT��__compact_unwind__LD �@__eh_frame__TEXT0@

h$

HX

PUH��1��E�]�zRx

_main �$��������A�C

因为main.s是汇编文件,也可以使用汇编的编译方法:

as main.s -o main.o

1.4. 链接运行库,生成二进制

给目标文件链接上运行库和OS信息,变成可以执行文件:

gcc main.o main

可执行文件因为有了运行库,所以就比main.o文件大多了。

注意main文件不仅仅有机器指令,还有操作系统的信息,否则windows/linux的应用程序可以兼容了。

1.5. gcc 编译过程产生的文件

*.c, *.h源码文件

*.i 预处理后的文件

*.s 汇编文件

*.o 机器码文件,可能是链接前的目标文件,也可能是链接后的可执行文件

文件之间的关系:

SoWkIImgAStDuTBGqbJGrRLJKD9BLkA2C39XZ68O8n_20AhbSaZDIm7g0m00

上述案例中产生的文件大小对比:

❯ ls -l

total 56

-rwxr-xr-x 1 wuhf staff 4248 6 13 10:48 main # main.o和运行库链接生成的可执行文件,比main.o大

-rw-r--r--@ 1 wuhf staff 45 6 13 01:11 main.c

-rw-r--r-- 1 wuhf staff 23 6 13 01:11 main.h

-rw-r--r-- 1 wuhf staff 211 6 13 10:55 main.i # 比 main.c + main.h 还大,是拼接到一起的

-rw-r--r-- 1 wuhf staff 608 6 13 10:47 main.o # 由 main.s 编译生成的目标文件

-rw-r--r-- 1 wuhf staff 485 6 13 10:37 main.s # 由main.i 生成的汇编文件

1.6. gcc 编译器干了什么

程序必须变成机器码才能被CPU执行,不管这个程序是OS还是应用。

gcc的最终目标是将txt的源码文件变成可以被硬件CPU识别的机器指令。

但是gcc并没有直接把txt变成机器指令,而是翻译成了汇编指令,汇编指令又转换为可以被机器识别的指令。

所以gcc 最核心的功能就是把txt的源码翻译汇编指令。

1.7. gcc 参数

-S Only run preprocess and compilation steps

-E Only run the preprocessor

-IAdd directory to include search path

2. 验证上述分析的可靠性

建立一个hello.c内容:

#include

int main(){

printf("Hello World!");

}

分步编译:

❯ gcc -S hello.c

❯ as hello.s -o hello.o

❯ gcc hello.o -o hello

❯ ./hello

Hello World!

直接将c文件编译成可执行程序:

❯ gcc hello.c -o hello

❯ ./hello

Hello World!

3. C/Java/Python 程序执行方式对比

3.1. C

gcc 把c文件翻译成汇编指令,再把汇编指令编译成机器指令执行,C文件变成了机器可执行的文件。

3.2. Java

java编译器的主要工作是把java源码文件转换为符合jvm规范的class文件;

jvm的主要工作是执行class文件,把class文件中的指令翻译成不同操作系统的函数调用。

java与C之间明显的区别是java程序的可执行程序就是java.exe,换句话说java的源码没有(不代表不能)被编译成机器指令。

问:Java 为什么不直接编译成机器指令?

答: 编译成机器指令会携带操作系统的信息,导致编译出来的程序不能跨平台使用。

问:class能否变成机器指令?

答: 如果class文件能变成机器指令,那么java既可以使用class来实现跨平台,一次编译到处运行,也可以实现更好的性能。

但是这样做的弊端是执行class前需要再进行一次编译,也是耗时的。

jvm本身就是C/C++程序,某种程度讲JAVA就是C的一个高级API,所以性能不比C落后太多,所以每次运行前编译得不偿失。

Java有JIT技术可以在运行时把把特定代码编译成机器指令。

3.3. Python

python是脚本语言,所以它不需要编译器,执行python的是它的解释器python.exe,所以python的可执行程序是python.exe,

它把python中的代码翻译成系统函数调用执行,从某种程度上讲python源码是python.exe(C/C++程序)一个复杂配置文件。

3.4. 一个编程语言包括什么?

对于脚本语言:解释器

有解释器就可以执行脚本了

对于不能编译成可执行程序的语言:编译器+运行时

编译器把源码编译成中间文件

运行时(Runtime)执行中间文件

对于可以编译成可执行程序的语言: 编译器

操作系统就是运行时

4. 一些反思

上学时候应该是大一的时候就学习C语言程序设计,学完之后对C程序如何编译,如何执行却没有具体的认识。

整体的印象是在VC 6.0中写好程序点一下运行代码就跑起来了,造成一个错觉:使用C就必须有VC6.0,C语言的执行就是写完代码再点击那个神奇的按钮,编译的作用是体现不出来的。后来学习Java就没有这种感觉,因为老师教学时用了一个文本编辑器+javac命令编译。

然后我们就知道了写java代码有javac和java这俩命令就够了,所以等到后面工作在Linux上运维还是ide开发都还是熟悉的配方,熟悉的命令。

但是C语言就不一样的了,只会用VC6.0,界面又丑,windows又升级还不好安装,基本上不想折腾了。

然后得出一个结论:受限环境有益,当工具不齐全时候更能深刻地认识问题, 就像我们老师说的那样,刚入门学习一个语言不要上来就用ide,会错过很多细节。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值