从c代码到二极管

从c代码到二极管

(介绍可以不看,甚至直接从第2部分看起也行)

从科学的角度来讲,计算机世界被划分为了N块,单单今天要讲的,将涉及,计算机组成原理部分和程序设计知识+一点点数字电路知识,还有一点初高中的物理知识。

今天要解说的主题,就是,从程序员(初级)的角度出发,当我们敲下IDE或者’笔记本’,上的代码并保存成.C或者.CPP/又或者.JAVA格式的文件后,无论是点击按钮编译运行,还是用JDK/CL编译器、链接器逐步打包,封装成一个.exe格式的文件,双击然后在屏幕上运行输出,比如(HELLO WORLD)。

从敲下代码,到编译运行,计算机内部到底经历了什么,让几串字符,发挥了效果?

其实有几本书从不同的层次都有对如上命题的解读,比如唐朔飞的组成原理,这是计算机专业砥柱课程,系统的将计算机底层硬件系统进行了讲解,将计算机底层各主要组成部分一一讲解,其原理、作用、应用,等等等等,也就是说,认真学习此书 才是程序员的“真·上乘内功”,当然还有国外的经典系列,比如计算机科学与艺术4大卷,我试过,只觉阅读难度太大,几页就放弃了,还有那本深入理解计算机系统,也是从上到下的解释了我们的主题,全面且深入。

稍微简单一点的,相对阅读难度简单一点的,还有国内的一本叫《穿越计算机的迷雾》,足够简单,不需要非常深厚 的工科背景甚至计算机知识,就能读懂。是个良好的过度。

还有一本叫《大话处理器》同样,比大话数据结构啥啥的 简直不要太好。

虽然从不同层次,都有将今天的命题详细讲解的资料,为什么,还要写此文的呢?

一,            其实是对自己的知识的总结,总是感觉自己是懂这个命题的,然而当我真正要将其从脑子里讲述出来时,才发觉有些知识还是模糊的,所以将其正真的梳理出来。。

二,            鉴于本人的计算机基工,其实也并不是特别牢靠,所以,以下内容都是,从自己一个非专业 人式,至少半路出家的,口吻说出来的,也许,对读者来说,接受起来更方便,那么,在以此为基础,继续学习深入的详细的知识,至少有个框架,视野更清晰。学习来至少对我的学习习惯来说,是更方便的。

三,            作为借鉴,对收错判嘛!

 

 

虽然说,是更简洁的解释,但因为命题本身的广、深,所以仍要以一定的线索与顺序,一步步将全体内容讲解出来,所以,千万不能半途而废,还有,因为内容体系太庞大,

需要读者不断地触类旁通,所以,加油吧!

同时,再次声明,我会尽力讲解的简单一点,尽量不涉及太多专用的一些知识。

 

 

内容梗概:(其实我自学的那点计算机知识,竟然都要用来为这个命题工作)

 

大体内容分为三部分,第一是一点准备知识,然后是上层软件部分,也就是程序+IDE/CL等工具,还有操作系统都干了什么,当然我会简单做出一些解释,仅仅点出大体的计算机常识性知识,全文重点还是在软硬件如何沟通,“几个简单的符号,或说命令,是如何驱动一堆精密的仪器真正动起来的”。

第三部分,才是从上层的高级语言指令,转化来的二进制指令,到底是如何驱动,底层硬件的。

 

二页起·正文

第一部分:准备

先简单说一下分析及实验背景。其实大体就是我学习中走过的路。

首先是最上层的软件部分,虽然我这阵子在学Jave,而且相比来说,Jave用起来比C确实简单不少,但鉴于一些情况,还是要以C为开发语言进行介绍,不过没关系,只是涉及到一点点很快就没高级语言啥事了。

       抛开IDE,用记事本+CL编译器+LINK等工具,来更深入的接触一下底层和系统等等。

然后是几款软件,到时会一一介绍到。

       默认Windows操作系统+命令行,Mac啥的,真心没碰过。

然后大概说一下后面两部分涉及的几大主题:

第二部分:

1.C语言程序,编译运行过程解析

2.编译原理+操作系统,一点点

第三部分:

3.汇编语言+计算机组成原理

4.数字(门)电路+二极管(晶体管)

 

大概罗列至此,下面一一介绍:

 

第二部分:上层软件

 

想想第一个场景,我们用文本编辑器写了几行最基本的代码,保存为test.c文件同时打开cmd工具,如图:

                      图一

这时,请先确保下载微软自带CL编译器,还可以选择很多种编译器,gcc等等甚至直接用vs或vc的IDE,也行,这里介绍一点知识,所以要用编译器一步步来。

       做到的准备后(只是听原理,也可以不跟着做没关系的),在命令行键入以下并回车:

C:\> cl test.c

记得将test.c文件放入当前工作路径中,如上就要放入C盘中最外层目录下。还有红色部分提醒读者记得是空格。

会得到如下输出:

重点是最后两行:/out:test.exe和test.obj

意思是,经过cl.exe工具打开我们刚才写的C代码源文件,产生了两个新的文件名称相同,但格式不同,意味着,内部的内容格式不同。接下来然我们解释几个知识点:

我们知道,操作系统是,夹在应用软件,和底层硬件之间的东西,也就是说,相当于,原本是想写一写代码,让后遥控底层硬件,然而,因为计算机体系的复杂,现代计算机,使用操作系统,将底层硬件的使用,屏蔽起来,对程序员来说,就是提供API供我们调用,间接驱动底层硬件。

比如,我们的test.c中的意图是,在屏幕中输出一行字符串“Hello World”。

那么,c语言编译器,将我们的代码包装,简简单单的printf函数,其实,是大量的由stdio头文件引入了其它常用库代码。

这里先说一下,一个*.C格式的文件在编译直到输出为.exe格式文件过程中,都经历了什么。

首先*.C文件会被编译,成为*.obj格式文俗称目标代码文件,此时是将高级语言翻译成了低级语言->汇编语言格式代码,他还是无法被底层的cpu看懂直接运行,所以,要再一次翻译,即由汇编语言 格式代码->翻译为直接的二进制的机器代码才行,也就是生成*.exe格式文件,其实他是能被windows操作系统认可的可执行文件,在其他系统上并非如此,甚至,文件管理系统都是非必要的,所以只要理解编译器或说IDE的工作其实就是帮我们将,c语言代码翻译成能被最底层cpu认识直接运行的代码格式,或者说操作系统认可的二进制文件才行。

那么,这期间还有更多细节需要了解,就靠阅读更多深入层次的资料了。

当我们生成了exe格式文件了,操作系统将其调入内存准备加载执行,这时,全部二进制代码,也许要先从外存加载至内存,同时,cpu内部有一个硬件称为IP的指令指针寄存器(可不是网络地址那个IP),当然这里引用了一些新的名词比如指令、指针、寄存器,无论读者是否有具体的概念,都会在后文找到答案。

这时,ip寄存器内部保存了我们所写的代码段的头地址,也就是整段代码的第一个起始代码的地址,那么cpu将按照地址从内存中将一定大小的一条指令加载进来,分析运算,输出,此时,刚刚ip被读取后,还进行了自加一操作,所以此时cpu将加载我们所写的程序代码的第二句,并重复刚才的过程,这其还有好多相关知识,真的不知从何写起,如果读者已经感到厌烦了,而又不想放弃计算机的话,建议直接改读组成原理,至少别急,别一心速成,至少这句话一直鼓励着我才让我一点点的积累成了现在的知识量。后文会尽量简短但全面的将更多的知识点讲到。(其实,有很多东西老师讲解,就是比自己看好,比如16进制其实就是2进制的缩写,每4位2进制正好对应一个16进制位的大小;再比如原、负、补码的区别与联系,还有-0和-128的关系等等)。

Cpu将代码一条条运行,就意味着,他听懂了我们的意图,并控制着整个硬件系统,顺序运行,实现我们的命令。对于前半句话我们还有几点要解释一下,如果想直接进入后半句话的讲解,可以直接进入第三部分。

补充知识点(1):编译原理

    我们知道,存在一些翻译软件进行语言的翻译,比如有道等等,同样的,编译器也是进行了如此的工作,他将高级语言翻译成为了一门低级语言(汇编),同样是对一些指令的表达,仅仅表达语言的不同,而意思是一样的,所以,编译器就起着这样的作用,同样,汇编语言,同样不能被cpu直接识别,所以,还要再翻译一次,而执行工具就叫汇编器,有关汇编,我们在下一节讲解,而这里说的,是从C到汇编的过程,也就是编译器的事!

就像学习英语一样,我们用一定的知识去分析,从而去认识并学习它,从而达到翻译交流的作用,对c语言的解释,同样是按照一定逻辑,一定方法进行的。尤其对于计算机来说,唯一性决定了,计算机语言,与日常用语还是有一定区别的。

专门有这样一门学科叫编译原理,就是讲解的计算机语言学的知识,比如自动机理论,有限状态自动机,正则表达式,等等等等,所谓词法分析语法分析,有机会可以了解一下,我一直觉得,这是真正烧脑子的部分。

 

 

第三部分:

上部讲到,一些工具配合操作系统,这些软件系统内的东西,共同生成了硬件真正能听懂的东西,于是乎一切被硬件接手,cpu开始逐条命令的执行命令。下面先从汇编语言讲起,在走入本文的核心命题。

 

汇编:

我们常见到的高级语言,如C,已经十分贴近日常用语,有宏观的语意在里边,高度的概括性,当我们日常描述一些东西时,非常简短的话,到计算机内部都是无法理解的,因为那可能要对应十分庞大的一堆代码文件。

反过来说,相比于人类世界语言,简洁却其实意义多样结构更是复杂,计算机语言,则完全相反,他用一系列指令列表就完全的定义了,他想要做的全部事情,在他的眼里,只有命令和数据,通过,一定的系统化工作,模拟实现并表达了,宏观世界丰富的语义。就像积木,只有简单,很少的几个基础形状,但只要数量足够,却能模拟非常丰富的形状。

直接来看看代码吧。

汇编语言区别于高级语言,其实反而和最低级的机器语言(也就是能直接在cpu上运行的语言)是完全相等的,他只是对机器代码的等价替换,比如:

 

上图就是 模拟 dos系统然后 用Debug工具模拟古老的cpu运行,第一行-r是显示当前cpu内部寄存器 状态(简便用法),第二行从开始的AX到DX是古老而经典的传统的通用寄存器组,他们大小为16位,所以 每个用4个0做占位符代表内容,4个16进制位其实就代表着16(4*4)个2进制位所以就是16为寄存器,其实他是两个8位寄存器拼接而成,所以还可用al、ah做高8位,及低8位寻址。其余三个同样,然后是专用寄存器组,这里简单介绍一个CS:IP,他俩组合起来,就形成了刚才所说的指令指针寄存器,内部存放的是16+16=32位的当前准备(或即将或正在)执行的指令的地址,如图 cs:ip 为06d5:010f这是16进制数,我用 -u指令查看了一下,提前被我写进去的(-a指令)的两行代码,完整的指令

是 –u 06D5:010F 也就是,显示此地址位置上的内容,我们看到,他被分成了两块,左边是,地址、空格一串不定长16进制字符串,右边是 较容易理解的 几行代码,我们按行来读取的话,每一行就代表了一条cpu能运行的最简单指令(还不是最基本的微指令,但对X86体系来说已经是一条基本指令了,读者最好继续阅读深入材料好好区别下,软件指令机器指令等等的区别,同样各种相关的知识,慢慢学,多了解)。

       也就是说,其实一行三部分:地址,机器指令,汇编指令。分开来看,地址就不说了,先看汇编指令。

    第一条:MOV AX,100

    在debug中默认数字全是16进制,用着方便。那么刚才这句话其实很好理解,这正是编程语言的第一次进步。就像c在低级语言和高级语言中的地位一样,能上能下。汇编语言,在机器语言和高级语言之间架起了很好的桥梁。

首先,他和机器语言完全等价,只是用一些人类更容易理解的符号替代显示。

比如第一行的:MOV AX,100   意思就是说,将立即数100[16(=16^2=2^8)]送入寄存器AX中去,我并不打算详细的完整的介绍汇编语言,这门语言让我非常喜欢,其简单直白的特点真的很美,如果把Java比作刀,C比作剑,那么汇编就是板儿砖,哪儿不服拍哪儿。

同理,第二句话,我们用了另一条指令ADD 数据是ch中的数和1,他的意思是,将ch中的数在其原本的基础上+1,并放回ch,

首先ch是?--其实就是CX寄存器的高八位,下面用-t指令我们运行一下,看看就很容易明白了,注意AX和CX(ch)内容的变化。

 

连续两次-t逐行执行了我写的命令,

第一条指令执行后,原来,AX中的0被我们的指令中的100(16)覆盖。

第二条指令执行后,我们可以看见,是CX中的高8位部分被赋值01,然而整体读取CX时,达到了和AX相同的效果。

简单的对汇编语言有了了解,我还想尝试着对汇编指令进行讲解。

我们看,上图ADD CH,01左边对应的 机器指令“80C501”,也就是说,这一整条汇编指令,就对应着80C501,还记得我说过最前边的06D5:0112是地址号,也就是说,DOSBOX模拟的这台计算机的内存条上的06D5:0112号地址上,存储着我们的机器指令80C501,观察上图两个地址号之差,0112-0115=3,也就是说80C501这条指令存储在CS:0112到CS:0114,这三个字节中,这里隐藏了至少两个知识点,一是内存基本单元大小是1Byte/字节,即8位/bit(2进制位),第二个知识点,它涉及到x86体系指令系统的知识,包括指令列表,分段寻址,栈、甚至分页、虚拟内存、包括流水线等等等等知识,都在组成原理书中有写,还有那本《汇编语言》-王爽,陪我体验汇编的宝书,非常之好。

我不写,一是没能力、没精力写,也写不好,去看大师们的吧,本文,其实是帮助处于半路出家的盆友们,带给我大学4年包括蹭课、自学看书,实验等等方式,学成结果,关于一线贯穿计算机软硬件体系知识的一个简单总结,希望帮大家克服,直接阅读组成原理等书的难度,其实我最不喜欢硬件,当初憋着跨考考研,还有自己的名校梦,所以,先把组成原理的书看完了,不过第一次尝试,完全失败,所以开始旁听,找各种书,帮我入门,直到蹭组成原理课半个学期,才差不多有了初步的认识,于是开始去重新审视《组成原理》,就没什么障碍了,至少能读下去了,不像天书了,尤其是,包括我们学校计算机学院系主任还有一位博士导师,共同开课,我就都蹭,听懂的再听,没懂的正好补补,反正,也算入了点门吧,这是我对自己的评价。希望对大家有用。

包括,同时开的汇编语言与接口技术课,真的带我进入了计算机世界的大门,也许这都是汇编的魅力吧,包括我后来自学单片机编程,不能说无障碍,可是,从各种角度对我产生了帮助。真的就像先学内功再练招式,事半功倍,手到擒来。

不过还要说明的就是,实践的重要性。同时,好老师的重要性也是的。

不过最重要的还是兴趣吧。

因为担心把自己的笔记本弄坏,10几天左右吧,几乎一天一章,看练着就把汇编语言王爽学完了,当然最后的小型c编译器没敢做,不够其他的都干了,最后三天自己写了个大练习,就是文字模拟人形机器人,上下左右移动,操控机器人动,不过很简单啦,百来行吧就。

不过,什么软中断,计时器,虚拟内存,都是那时学会的,加法模拟4则运算,高级语言原来就对应着汇编语言的几条最基本指令。

在我看来,整个汇编体系就3条:

Mov,Add,Jump。不是对的,就是个比喻,别当真。

23点了,不说碎语了。

关于机器指令,我再说一句,算个引子。

可以说,计算机或者cpu只认识0 1 0 1,那么他是如何对刚才的80C501进行解析的呢?,他怎么就认识80C501就是ADD CH,01的意思的呢?

这就是X86指令体系的事情了。听闻,处理器架构,它不仅仅是硬件设计,更是匹配其上逻辑电路,对应的指令体系,合作运转。

简单来说个开头,就是大家看

80     C5    01

Add    ch     01

似乎是对应着每2个机器指令的数字,意味着一个汇编指令短语,其实并不完全如此。比如最后的机器指令的01,也许就是我们写在汇编指令中的立即数01。

更深入一点,ADD叫做指令代码,对应着在cpu内部有一个指令列表,上边存着这些固定指令的固定操作细节,也就是对应操作代码的转移地址入口。

其内部隐含了当前指令的编码细节,于是,cpu就能安全的将代码区分为数据和指令了。从此,反正,第一次明白后,有种很神奇的赶脚。

甚至,还知道了BOIS到底是什么,操作系统是啥,这就是汇编的魅力。

 

第三部分(多为硬件知识)

在前两个部分,我们将c语言代码的运行,在软件层的运转一步步引领到了,最内层的cpu跟前,在DosBox中模拟运行了一下,不过,现代计算机可是复杂了很多,我只是分享了一下经典知识。

接下来,cpu读取到了 80C501,首先读取到了指令代码地址,于是查询指令列表,读操作序列,于是,软件序列,终于在此处得到从软件到硬件的交换,也就是说,底层的硬件们,终于在cpu的监控下开始正式运转,以实现我们最开始的C代码。

接下来的知识可能更枯燥,挺会吧,就快结束了.

计算机将各种复杂的操作,简化设计为几条基本的指令序列,也就是说,

80C501:ADD CH,01这条软件指令,对于cpu来说,其实太大了,在java数据库中,也会听见所谓,非原子性操作,所以。

计算机,将软件指令拆分为几条最基本的,最简单的,所谓微指令,也叫机器指令,能在一个或者有限个很短的机器周期内完成的操作序列。

这里又涉及到了,时钟周期等等的概念。我们知道,计算机内部,是靠电驱动的,也就是说,内部保存的是电信号。然而电信号,并不能长存,就像常说的,必须把文件保存在外村硬盘上,否则内存上的东西,一关机就没了。

不仅仅如上。

这里我们引入第一个非常见、专业名词,触发器。

他其实是,前面我们提到的寄存器内部实现。

前面一个例子中提到,1byte内存对应着8bit即一个字节大小的内存含8个二进制位,例如c中的char类型变量,8个二进制位,所以1个byte最多保存256种数据,也就是能区分256个数(而每一个数代表的意义是不一定的)。

那么,1个寄存器基本单位内,是什么物理硬件实现的8个位的定义的呢?

就是8个独立的触发器。

简单来说,他有保持电信号的能力,这个所不是永久保存的意思,我们的硬盘是磁介质所以能永久保存,而内存条、寄存器都是电介质的,所以断电就会失去数据,再上电又按照一定规则置位。

这里的保持的意思,其实是,说上电时,保持某个数据,不会因输入而改变,所以,当别人从这里读取的时候,只要不是用其他指令修改(赋值/置位等),仅仅进行读取操作,都会得到最初保存在这里的数值,将8个触发器看做一组,叫做寄存器,那么,一个触发器保持2种结果,8个就能保持256种结果,但是1个寄存器只能保存1个结果,这里提示下种和个的区别,相当于地址和地址内数据的区别。

然而,触发器内部又是什么更具体的东西实现的呢,别急,这不算完,不到二极管,咱不算完。

无论学没学过,数字电路或者骊离散数学,但都应该听说过‘与’、‘或’、‘非’逻辑。

在电子电路中,还有一种和锁存器处于同一级别的逻辑元件,用于控制电路的信号。

而他们的内部就是一个个由叫做与或非门的逻辑门电路设计组成的。

下面摘一张百度上对触发器的解释的原理图,不必深究,数字电路或者电子学上都有详细介绍。这里指点出联系。

 

 

其实,在很多地方,我都不是很懂,比如刚才我到这,一直以为寄存器由锁存器组成,触发器是另一回事,一查才想起来,完全错了,然后改的稿,删了好多,同时决定不写细节了,大家自己去找本书,认真看吧,想学的话,或者仅仅了解个大概,或者仅仅满足下好奇心,也是足够了,我早说过我懒得学硬件,还是有道理的,不过,最近学Java发现其实好像差不多,哎···还是游戏比较酷。

 

       不说触发器了,反正,代码存储在内存中,cpu将其以指令加载进来,通过解析,识别指令代码,加载指令序列,并执行。接下来,以向屏幕输出一个字符为例,解释一下,最后的执行到底是怎么回事。

 

       首先要解释一下,其实,所有的最上层的表现,最底层仅仅是,数据的变化。

       计算机内部将各种外部设备当做内部资源,使用。

       和他们通信,做到交互。

       敲击键盘,就是从键盘外设向cpu输入数据,

这是一个事件,cpu会监听这样一个事件,并去查询,输入的数据,再,根据当前指令,将其转发。

比如,8086将内部内存地址 0xB800开始2KB大小的内存映射为屏幕上的显示。

也就是说,向这段内存写数据,就相当于向屏幕写数据,

例如:

       MOV B800:0000,FF

就是向0坐标的位置写了一个字,具体的文本模式彩色模式,什么RGB高亮+内容啥的,具体的汇编王爽上有.

也就是说,无论输入输出,其实就是cpu检测到事件,然后将数据,在内存(寄存器)间来回传送。

而当涉及到规律性的变动时,jump指令和Add指令等的来凑热闹。

所以,现在只剩一件事了。

门电路到二极管。

知乎有大神。。。哈哈

http://www.zhihu.com/question/26998618

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值