从汇编角度分析C语言的本质(一)

来源:互联网 发布:植物常见科 知乎 编辑:程序博客网 时间:2024/04/27 19:00

      其实,本人学c语言不算很久,也没有那些大神随便几万行代码的经验,说白了,其实就一个入门的 菜鸟。 但是,从迷迷茫茫的开始接触c语言到现在自认为对c语言有半点见解,感觉某些经验,思考过程还是很有记录的意义,对于那些高手来说,这些肯定是他们早就觉得像吃饭一样平常的事情,但对于刚自学或跟着大学课程来说的初学者,很可能这个经验会让他们像我当初一样恍然大悟,并发现c语言的美妙。

  由于时间有限,本人正忙着学arm,所以就挑重点多了。今天,主要想说的是如何重汇编角度,或者说编译的角度来理解、分析c语言。

1,、c语言的本质

当初刚解除c语言,只知道是用来编程的,觉得挺神奇,但由于没有微机原理和计算机体系的认识,根本不知道编程到底最后如何运作。所以对于c语言可以编程这个概念,自然也是表于纸面的。那时,也没有学汇编,因为这个原因,反而不会太迷茫,比如声明一个变量,int a; 声明就声明罗,变量就是可以改变值得一个数,也觉得还好吧,所以就这样学完了谭浩强教授的《c程序设计》,也觉得还能理解。在电脑上,运行也可以。对于c语言也就记住它是高级语言,汇编是低级语言。后来就接触汇编了,再后来单片机,dsp、arm什么的处理器学了几个,每次学这些处理器,难免会接触其汇编指令集,还有汇编程序设计。但用汇编编程时,觉得挺好的,因为那些指令都是指令集上的,想完成什么加减的,就用相应指令。于是,开始觉得有问题了:汇编编程直接用指令集,和一些伪代码,但c语言为什么不用到指令集呢?你可能觉得我很幼稚,因为大家都知道c语言是高级语言,编译之后就有真正的指令了。对,确实这样,这些我也都知道,我想说的是,究竟所谓的编译是怎样的?到底高级语言为什么叫做工具?好吧,不啰嗦,相信这些对于有兴趣看这篇文章的人都明白这个过程,至于不明白的也不会对这篇文章有兴趣。我就直接说我的一些感悟了:所为高级语言(例如c、java),其实真正本质在于它的编译器,否则你那段代码 赤裸裸的只是一段字母的组合,但是交给编译器之后,编译器会”识别“这些字母的含义,之后根据处理器来编译成相应的汇编语句,之后再变成处理器可以执行的二进制机器码。打个比喻,编译器就像一个翻译,你说一段话,机器是不明白的,编译器就把它翻译成机器可以明白的而二进制代码。所以高级语言本质是一种工具,一种翻译工具。当然,这个翻译者不是神,你只能按照它规定好的语法来编程,否则,它也听不到你想说什么。当你知道所谓开发一门语言不就做一个编译器,你就明白什么就高级语言。夸张一点,中国人想搞一个中文的高级语言也可以的,比如,就一句”让怕p1.1口为高电平“,编译器就编译出一句相应的汇编语句。开发一种语言很难,因为你的这门语言要可以完成很多功能和操作,那么语法问题就要解决。

 

2、重点从汇编角度分析几个c语言的问题

       1、为什么要声明           很多书就直接说声明为了告知编译器这是一个什么什么变量,到时具体的含义是什么呢,我个人的理解是(我没有看过编译原理,只是觉得这样理解是可以验证没多大问题的),其实当编译器开始编译后,遇到你声明的那个变量,如int a;  这是其实编译器做了很多东西,它就已经为这个a变量分配一个相应长度的内存了,之后你用这个a,它就把相应地址给你操作,而如果你不声明的话,到后面遇到这个a,编译器不会认识她,因为若作为一个字母,也应该是'a',所以会报错。而int 又是怎么回事呢,你会说这是声明a为一个整型变量,但问题是,具体操作是怎样的呢?其实,所谓声明类型就是告诉编译器,比如这个a,以后用到a时,编译器你就帮我把a的地址开始的4个字节(int也有可能2个字节,看平台),作为a的内容。所以如果你把a声明为char的话,到时编译器就会把a地址开头的一个字节作为a了。所以应该明白类型的意义了吧。

    2、指针为何物   指针的定义是保存地址的变量。 但,到底用到指针时汇编是如何编译成相应汇编语句的呢?  例如,定义一个指针   int * a;编译器遇到这个声明其实会做什么呢?其实当编译器遇到这样一个a后,首先根据类型int分配4字节的内存,之后把首地址保存在变量a中,(a有自己的地址),同时编译器”记住“ ------以后再遇到a,比如我们应用*a=5;时,编译器就会编译完成以下操作:把5赋值给a变量中保存的地址的那个单元。所以,指针就是这样。当然,指针指向不同类型时编译器要完成的操作会很多。但是编译器的本质就是”解放程序员“————————————————一句c语言有可能相当100句汇编。所以谁还愿意用汇编在苦逼的编程。

 

  3、函数为何物     当我们声明一个函数时,编译器到底要做什么呢?其实,当我们  int  add(int a,int b)时,编译器会根据函数的返回类型分配一个相应的内存单元,之后再去分配一段内存,这段内存就用于放这个函数的代码,之后但我们调用函数时,其实编译器就会在那边加一个跳转指令,让程序跳到这段内存得地址。所以,调用函数就是跳转。   对于返回类型,其实只有明白编译器只为一个函数分配一个类型长度的变量用于返回,你就明白为什函数不能返回多种类型,当然你想返回多种类型也可以,只是要用结构体或指针

 

 

写到这里突然发现这个话题很大,很难有条理的说的清,深感自己见识不够,第一次写博客,所以大家多包涵,对于以上观点,纯属个人爱好而发表,没有经过什么严谨考证,所以只希望读者能有所启发,因为明白这些后,对于学下去很有好处,不会一头雾水。我最想表达的一个观念就是,要学好,理解好高级语言,就要有一个意识:从汇编角度去想。这样,你就会明白一切问题。c语言等高级语言真的很美妙,因为汇编编程时枯燥的,甚至无趣的,但c编程时一种创意,创造的过程,你会为自己编写的代码感到自豪。因为,简单的几句语言,就相当一堆的汇编,重点在于这些汇编还是很美妙的组织起来的。c就是一把利剑,发挥好,会发现她的巨大魅力。而从汇编的角度理解她是最好不过的,当然学过编译原理的读者,肯定理解c没压力。 

 

一点小灵感的诉说,希望能给哪些和我当初一样不明白高级语言的魅力的读者带来一点启发。同时,也为了记录自己的成长。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

原创粉丝点击