Contents
一切从0开始
讲C语言之前,先说第一句鬼话,如下:
C语言,只是一个编程语言,对于工程师或程序员无非是个可选择的工具。是否选择,根据设计目标和任务以及执行团队的习惯、特长。而工具,从此篇开始,新手始终要明确,C语言是用拿来用的,不是拿来研究的。
C语言可以简单的总结为,根据一种标准,提供一套语法,使用对应工具,将符合语法和工具要求的文本设计文档,转换成对应机器可以执行的指令集,以接受其他程序的调用。
和很多高级语言例如C#,JAVA不太一样。C语言虽然称为高级语言,那也只是相对汇编语言等早期的面向指令的语言。而C语言从语言的高级程度来谈,更应该定性为,面向计算机组成原理的语言。学习C,应用C,利用C。不可避免的需要理解计算机等相关知识,以实现利用C,将设计目标,转换成靠谱的逻辑,以利用计算机设备,进而实现。
而其他很多高级语言,已经帮你做了很多事情,不要怀疑C的低能。其他语言可以做的事情,C都能做,而C能做的事情,你使用其他语言设计 未必能做。从好的方面说,这是C语言强大和迷人的一面,从坏的方面说,为了吃口饭,而不得不开始耕种稻米,可能米粒还没见着时,你已经 饿死很久了。
话回正题,一切从0开始。数字计算机(广义的,包括手机和电视),无论你是否知道,目前绝大多数的,都是采用二进制。二进制,自然就是0,1。更加准确的描述,是有限数字计算机。拆开来说,就是一台计算的机器进行数值计算,是二进制的计算方式,但是所有数值均有位宽,也即上限。
位宽,是啥,哈,用于存储或逻辑上描述一个有效数字的存储空间。由于是二进制的,每个位只能描述0,1,所以多个位组合在一起,才能描述更大的数值,而这些位作为一个整体,所具有的位存储的个数,我们可以简单称为位宽。
位宽和计算又有什么联系?一个简单的加法,255+1=?
如果稿纸或大脑演算,很简答,256.如果是位宽为8位的存储空间,那么答案就为0 。
不要怀疑 255+1=0.是错的。类似的情况在你的钟表盘上也有。11点59分59秒后,过一秒,通常显示的0点0分0秒。一样的道理。如果你没有
其他辅助信息来说明,是新的12个小时,只是让个机器来读当前表盘的数值,一样是11点59分59秒+1秒= 0点0分0秒。
或许有人要说,1位存储表示2,8位就应该是28=256,应该能保存256个不同值,为什么256不可以描述。这就得重复强调下标题,一切从0开始,因此,256个不同的数值,所对应的是0到255,而非0到256.
因此,在数字计算机的世界,0一定是起点。位宽如此,地址也一样。计算机的惯例,我们对存储区域,每8个位,我们认为是同一个地址,简单理解,目标是要盖一个能有1000个房间的大楼。那么早期的历史原因(如同相关部门一样,各种原因,这就不解释了,你也没必要细究)。每层有8个房间。由此,1000个房间的大楼,我们盖了125层。每层的层数,我们称为地址,而实际每层中各个房号,我们认为属于一个地址内的不同位。
再次强调,传统的一楼,在计算机世界里,被定义为第0层。也即地址为0.而每层8个房间,也因为历史原因,房子是个大通道,从东向西依次排开,我们对房间的定位就有了。最东边定义为0号房间,依次最西边,定义为7号房间。
因此,第7位,对于8位宽的存储空间,就是最高位。例如我们经常说的32位,64位,最高位也即31位,和63位。
这里衍生说一下,32位系统,64位系统。等等。32,64究竟指什么。公说公有理,鬼说鬼话题。鬼话如下:
32位系统,从硬件角度看,是能提供32位数据并发传输,计算,存储的系统。从OS角度看,最小指令为32位,逻辑寻址宽度为32位。
当然你可以用64位的机器,装上32位的OS,如同有WINDOWS XP32位情节的朋友。
对上面的一些所谓的术语展开描述一下。数据并发,如同马路上的行车道。我们通常说,双向4车道,大多数情况是指,由东向西有两股车道,
由西向东有2股车道。我们在计算里可以称这种传递数据的通道为总线。由于历史原因,一个车道,根据控制,即可以从东向西,也可以从西向东,我们简单说就是双向时分复用。也是通信里说的半双工。那么一根线,一个时刻可以传递1个BIT。我们同时有32根线,自然可以同时传递32位数据。这种是并发。与之对应的是串行。如果总线只有32位,你需要传递64位的数据,怎么半呢?先传32个,再传32位,传过去了,再整合起来。
指令是什么?就是命令和一部分与之对应的数据的组合。例如,你去操练,一共有,立正,稍息,向左,向右4个命令。那么我们至少需要2位存储来描述4种不同的标记。如果上述对应的指令编码是0,1,2,3。那么二进制0b10就等于告诉你向左。实际计算机指令比此复杂,后续章节会在对应位置给予进一步解释。此处,你理解指令是能让计算机去实现不同动作的数据就可以。指令,本质就是数据。无非他被机器执行了,就成了所谓的指令。他并不神秘。其他数据不是不可以执行。而是操作系统为了保障这些数据确实能“正确”的执行,而对某些文件,加了各种属性,典型的如linux中要求是增加可执行属性。
鬼话: 如果你学习和使用C,就要有种学习其他高级语言所不具备的魄力,一切皆可为数据,我所关注的无非是存哪,位宽,操作的逻辑是什么。因此,C语言,从这个角度来看,是一种面向数据,面向存储的语言。地址和位宽,是C语言开发中,始终关注的。或许JAVA等高级语言的程序员会经常高贵的说,我想怎么怎么样,来设计。但C语言程序员,需要非常谦逊的说,它能怎么怎么样,来设计。
寻址,只是个术语,有啥用?其实就是懂的人,为了简化描述并与不懂的人保持距离的一个简单说法而已。寻址实际是个非常抽象的动作。也就是说可以通过一个数据,将其看作是个地址,并能由此找到对应的空间。如同,你的大脑假设只能记住所有地球上的门牌号码,你已经牛到可以证明你是火星人了,但你却无法找到你在火星上家。
实际各种系统,有千奇百怪的寻址方法。你与其对各种寻址方式和方法保持敬畏,不如事实在在的查查资料,倾听下硬件设计者的心声,通常潜台词是“我也不想啊,没办法,为了实现这个目标。我只能用这种办法”。
鬼话: 敬畏和同情是两类不同程序员的不同心态。你可以敬畏VC++的MFC库,你可以敬畏JAVA的广泛的类包,但如果你是C程序员,一定要满怀怜悯之心,理解,同情,硬件设计的无奈。因此,C语言的学习,不单单是一个语法的掌握,还包含了硬件组成原理的了解。
补充一段可激起战争的言论,C与C++的对比。
简单一句话,C是面向模块和过程的,C++是面向对象的。由于计算机的性能提升,大量并”不高效“的更高级的面向对象语言,例如JAVA,被越来越多的使用,以解决面向对象方面的问题。而C++由于是早期的面向对象语言,被逐步沦为处理底层(也即非应用程序)的任务。而非应用程序的底层任务,通常需要面对设备,通过模块和过程化的方式实现,由此,C++在现在,更多的沦为为了面向对象而面向对象的设计工具。
一些比较普遍的现象如下: 1. 非常棒的C++程序员,通常都熟练掌握C设计技巧和方法。 2. 设计的C++程序,通篇是C的模块设计思想再套上面向对象类的方式。 3. 越熟练掌握C的程序员,越来越不喜欢使用C++。
总结一句话,C++就是C++,和C没有任何关系,只是历史原因导致不叫D,而叫C++。你要么专心学习纯面向对象的设计语言,要么专心学好面向模块和过程的C语言。打击C语言学习的朋友们,C别指望在越来越复杂的软件环境中编写应用系统。安心做好烧窑工,为其他程序添砖加瓦,别想着借点面向对象的概念,玩什么C++,以认为可以用一个长得像C的面向对象语言解决应用问题,即无必要,也不现实。
衍生讨论下,面向对象和面向模块或过程的区别。
简单说,面向对象,看到的是个体之间的差异与关联。面向模块或面向过程,看到的是行为之间的差异和关联。
举例说:一群人在主题公园大广场上游玩。
面向对象看到的是,有一群人,有男人,有女人,有孩子,这三个是一家子,而那10个是一个旅行团。落在一个团体里,看到了个人的差异,落在一个广场上,看到的每个团体(实际是个体)之间的差异,以及相对的关联。这个团队在大门口,那个家庭已经在照相摆POSE。
面向模块或过程,看到的是,广场有大门,有拍照点,有厕所。无论什么人,进入,需要收费,无非大人一个价格,孩子一个价格。拍照点,不好意思,和世博会一样,用SSS型的栏杆栏起来,你不排上40分钟,我不会允许你在雕像面前拍4秒。至于厕所,男厕女厕不能乱,大号小号有区分。
看到没有。面向对象,更人性化的关注实际的情况,人群,也就是应用,设计者更如同一个新闻播报员。而面向模块或过程更关注资源和操作方法,设计者更如同公园管理规划者,虽然男人女人老人孩子有区别,但是谁都一样,即不能在广场随地大小便,也不能在厕所里乱拍留恋。
从设计角度,每种方式都没有谁可为,谁不可为。但由于更多更复杂的业务应用程序,更应该考虑现实逻辑,采用面向对象更合理,而更底层的专用模块,必须要考虑设备的特性,因此面向模块和过程的思想更有效。
而C++是什么呢?刚改革开放的80年代时,缺乏新闻工作者,而将一批公园管理人员转行得来的从业人员。由于没有经过理论的教育,相对那些经过专业培训的科班出身的美丽女主持而言,显得对工作不够得心应手。而讲解时,还不停的带有公园规划的言论,没办法,历史原因,结果就是面向模块和过程的讲解中,套了面向对象的路数。效果各自评价,我不再多言。
下一篇:从一条内裤说起