用新浪微博登录

只需一步,快速搞定

 找回密码
 立即注册

用新浪微博登录

只需一步,快速搞定

查看: 2283|回复: 4
打印 上一主题 下一主题

新手编程导论(五)

[复制链接]

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

跳转到指定楼层
楼主
发表于 2011-10-22 15:30:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式 |          
第4章 语言最小内核(C)

4.1 C与C++是二种不同的语言
C语言的最初的版本是起源于B语言的,后来经过发展,又经过了多次标准化(第一次民间标准化是C语言的二个创始者K&R写的一本书,C是最初作为UNIX专用系统编程语言出现的),分裂成了二支,在C89标准上面加上OO,加上Template,就形成了C++(C++是C89的超集,当你手中拿的C++教材没讲基于过象面向对象和模板并且你需要的不仅是一本C的教材时,你可以现在就扔了它),第二支继续独立发展,发展出了C99,目前最新的C标准是C99,支持并实现了它的编译器市面上比比皆是。
关于C89与C99方面的差异有一些是根本性的,因为实现的原理根本不一样(是编译器方面的差别,而不是库级逻辑上的差别),比如C++用Template技术实现的数组版本和C99的数组..
所以,C++除去C89的那部分才是C++的主体(所以说学习C++是学习C语言和C++语言这二个过程,我们知道++是C家族语言中 特有的运算符,C++这个表达式表示,第一次的运算过程只首先取C的值,第二次及以后的运算过程才在保留原值的基础上开逐次始加1),C++为了成为多范型语言,先是杂合了C的很多特性,提供了指针,位,函数,流程这些基于过程的开发支持,为了成为基于对象和面向对象语言,又实现了一个运行期OO — 其中有运行期多型机制(这是C++之父"发明"的),再后来是在没有任何原C的编译技术的支持的情况下发展出了一个Template(也是C++之父所在的研究小组"发明"的),是C++首创的独立编译技术(并由此"发现"了C++的编译期多态和实现了Loki,Boost MPL库等),STL就是用了C++的Template而出来的东西,STL是面向运行期的,而Boost MPL库是面向编译期的。
C99的数组跟STL的数组就是大不相同了,,一个是C上面的,一个是C++的模板技术上面的,有着不同的实现原理,编译支持基础..
在C中,数组就是原生Built-in的,,数组就是连续的同类型数据在内存中的分布,,,注意,1,连续空间2,同类型数据,,如果不是连续的空间就不是数组,,比如用指针link起来的就是链表,而不是"数组表",,注意"表这个说法",,数组是一种表,,因为它用索引下标索引数据对象,是一种key:value对,而链表也是2同类型数据,,
在STL中,模拟数组比如Vector,List是用模板来实现的..这二者之间明显存在差别,静态数组一般直接用C的数组,,但是正因为C的原生数组是没有边界检查的,编译器根本不保证这个栓查全部交给程序员来处理,,而STL版本的模拟数组就会非常严格..
这就是二者之间的差别

4.2 C的数组,指针与字符串
(我这里讲的都是C标准)
C只直接支持简单的数据类型,只有简单的Int,Float,Char,Void,这样的数据类型可以直接定义使用(并可作为函数参数传送,但数组就不能直接被传送,需要转成它的指针形式 — 一个32位长整型数被传送,,因为它不是First Class),,其它的高级数据表示比如字符串,数组,都是在简单数据类型之上模拟得到的,,,是库级的逻辑,,编译器并不直接支持..(C编译器没有提供对字符串String的Built-in支持,只有Char和Char *,C把它作为库级逻辑的String来抽象)
C99在库级新增了_Image,_Complex,_String这些数据抽象(相对C++来说)..
所以C的指针类型几乎跟数组,字串这样的逻辑同胞共母,字串本质是Char * 数组,,数组是内存相续的同型数据,用指针变量来表达数组和字串几乎浑然天成(数组名就是指向第一个数组元素的指针,类型为:"(基类型)指针变量名"这样的形式,,而且字串直接被定义成char[]的形式,,数组大小一定要程序员方面保证容纳字串大小+一个/号的大小,字符串函数大量涉及到指针比如strcat,C有一个标准的字串实现,cstring.h,C++有一个STL版的字串,C++还有一个原生版的string.h,特定的编译器也有特定的字串实现),,,C就这样把所有的东西统一于简单的"简单类型"..
当然C也提供了union,struct这样的结构体来表达比简单的类型来抽象一级的类型,其实C也可以表达OO(不过它并不承诺一定要实现运行期多态,继承等OO语言的标准技术,,有一本<<C支持面向对象技术>>的书讲解到了相关的技术)

4.3 C的输入与输出流
C++版本有个Iostream(Cin,Cout就在里面,实际上C++的IO库很大,是一个复杂的基于对象的模板系统),C也有它的Stdio.h(有Inputchar等和Printf()这样的函数),这是C语言的标准(库)独立于所有的硬件和软件环境,是语言本身的因素,,,一门语言的IO机制是很重要的,比如,JAVA的I/O封装得很完善,,它细分成了多个OO表达的"流",极大地方便了程序员。
i/o绝非仅仅输入输出这四个字这么简单,首先这是一种语言机制(就跟语言提供异常处理,这样的语言机制的地位一样重要),是关于这种语言对向它输入和由它输出的所有抽象的全部集合,它涉及到一门语言如何处理与系统的交互,如果将用户输入转成该语言写成的程序所用,,如何看待OS"文件"的概念.并发展出一系统概念,如input steam,file steam,等等
在PC的架构中,语言是高于OS的(一般在一个系统的架构中,开发层是高于内核层的),Windows是用C写的,C有它的I/O,是先于Windows的,一门语言并没有具体的数据类型,,比如unsigh,sign这样的区别是来源,起决定作用的还是硬件,,C语言只是对它们提供了一些名称指代,,比如int在有些机子上是32位在有些机子上是16位,这对考虑一种程序的可移殖性是十分重要的。
在C的眼光中,一些输入输出都是某种流,语言接受用户输入,或者程序进行输出,先以内存作为根据地进行缓种,,缓冲分为二种,一种是缓冲文件系统(这是C标准的文件系统,,即不是一次性输入用户数据到程序中,而是输入一次缓冲一次),另一种是非缓冲文件系统(每次输入就完成一次绝对的i/o),这是,C把显示器,打引机像成标准输出,把用户输入键盘,想象成标准输入,,并把它们看成"标准输入出流",,,把OS的文件想象成filesteam.

4.4 C的类型系统与表达式
任何语言都有一个“类型系统”,比如C++直接支持类(UDT)为它的First Class,,Lisp这样的语言支持直接传递函数指针(因为函数是它的类型),,,就C来讲,,它支持primitive types,即普通的Char,Char *,Int,Int *,Float,Float *,Void类型。。
到底什么是类型呢,C++ template的type跟class有什么区别呢。。

4.5 二进制指令看循环
大多一门语言都提供了流程控制,,形成了各自的语言关于流程语句的语法要素,,语法是一种形式(所以称语言是形式语言),,语义是一种意义,,,
其实循环,跳转这些东西来自于汇编语言,,,高级语言接纳了这些理念(因为汇编语言几乎就是机器逻辑,高级语言提供类汇编语言这样的机制是为了符合平台逻辑,,,况且高级语言最终要编译成汇编语言和平台逻辑,,循环语言要最终被还原成汇编语言的形式,这些处理速度就可大大加快),,,发展出了它们关于循环,跳转封装了的语言机制..
C语言最终要编译成汇编语言和平台逻辑,,循环语言要最终被还原成汇编语言的形式,,这就是调试的由来,,,调试分语法级调试和语义级运行期的错误..
回复

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

沙发
 楼主| 发表于 2011-10-22 15:32:53 | 只看该作者
4.6 所谓指针:当指针用于设计居多时
指针是C语言中的一种"语言机制",,它导致的差别在于
如果用得一般,指针就是一种普通的工具,仅仅在给函数传地址改变实参,数组的定位本质是指针,,这些课题上达到顶点
而如果C语言的指针用得好,,,C语言就会是另外一种语言,
那会是一种什么语言呢,那会是一种advanced pointer c lanuage(增强型指针C语言,,指针使C变为设计语言就跟C#高级语言一样,而不再仅是普通意义上拥有指针作为底层机制的中间语言)

因为指针是C语言唯一的"抽象语言机制",我们这里提出"抽象语言机制",说明可用于设计,,,比如C++有"OO","范型"等等(很多书上讲解C++没有讲解这是对的,因为C++的语言机制中,只有OO和范型是它自己的,而指针几乎是C语言唯一的抽象语言机制)

指针被用于设计时,,它的用法有哪些?? 这就是学C的最高境界,

首先指针是一种底层实现和设计通吃的语言机制汇编语言中也有指针,比如
mov eax dowrd ptr [某一地址]
mov edx dowrd ptr [某一地址]

这样的结构,,说明指针在这方面是一种内存地址的指针,,然而当指针发展到C的指针和C++的引用时,,又形成了更高层的逻辑,,,

4.7 指针成就的C语言
幸好你没有把C跟C++放在一起学,,C是c99,C++是C89,,可喜可贺
学C,,要学透就学指针,,,要学全,就要学C的标准库
指针不单是控制底层的工具,,,也是C的抽象语言机制
1) 字符串,C的字符串跟指针密切相关.C根本就是用内存来控制字符串的.而C++的Iostream.h你去看看,,全是抽象了的模块,你根本不需要深入内存,二者根本不可同日而语,,这是因为C就是站在底层去构造字符串逻辑的,,而C++隐藏了这些,,不让程序员知道..所以C最适合当系统编程语言,而 C++控制系统的能力却没有C强,,,一个很好的例子就是可嵌入开发,C++根本不行,因为C++更多地是一种应用开发语言
2)数组,C的指针几乎(我说几乎)等同数组,前期的C根本不能把数组当参数传递,,后来的C标准支持了这个观点,,因为数组在C的观点里就是内存地址.因此用指针完全可以控制数组,,函数可以返回一个指针以返回一个数组,,,数组也可以用指针而不用索引来定位并操作它的元素
3)位操作,,就是所谓的bitwise了,,这个跟指针的关系就更不用说了

综上所述,,C是靠指针来进行设计它自身的,,,而且,C是靠指针来解决C能解决的程序问题的..因为C不仅是一种语言手段,,而且是一种语言抽象...
网上有用指针实现C++的OO的文章,,读完它,你就发现C通过指针机制还可成为设计语言,,,什么是设计语言呢,,C++,VB,RUDY,LUA,DELPHI都是设计语言,而C就是底层语言.

祝好

C是系统编程语言,,一般谈到对系统编程,,,就是数据结构加算法(当然,系统编程的真正概念是指:socket,graphics,IO,gui这些平台支持逻辑相关的层面),,,编译器前端的构造就是一个大算法,,,运行时就是一个大数据结构,,,操作系统作为语言运行的环境,,考察它的实现过程,也是数据结构加算法的集中体现,
如果你真要学透C语言,,,,第一要学习C语言是如何来的,,这就是编译后端了(动态运行期的类型信息),,,第二要学习语言本身的机制,,当然重点是指针..因为指针不单是内存地址,,,而且是一种语言的抽象机制,,,C语言只有指针这种抽象机制,,就像C++的OO,范型一样
数据结构加算法是系统的观点,,所以容易跟C语言结合,,,C语言也因此被用来系统编程,而VB是RAD,,抽象了太多底层的东西,无所谓数据结构加算法,,所以被局限于代码组合和快速开发...因为它的接口就是控件属性和方法,,,它的功能模块就是控件..

其实OS不需要一个语言,语言只是为了开发应用而出现的,OS可以不要它(语言编译器也属于系统软件),更确切来说并不需要一个编译器,,它只需要一个编译器的后端,比如运行时,或者仅仅一个解释器。有了这二个就可以执行源程序了,这二者之间的接口要明白,因为解释器可以直接执行编译器前端生成的中间代码.
而且VB的运行时面向的根本就不是真实机器,,VB是一种架空的语言..因此它的语言机制也是构空的,,,不是面向系统的.因此无所谓数据结构加算法

4.8 指针是语言的一种抽象机制
指针是一种语言的抽象机制,而不是仅是语言用来控制低层的手段(指针指向变量,而变量是内存地址)
指针有什么用呢,,指针用"指针本身"来指代"它所指的东西本身"(虽然实质不同, 一个是指针变量一个是指向的变量本身,二者除了意义上指代与被指代这层联系之外,其它方面没有任何联系,从变量的三个方面来看,
1.变量的型别,,每个指针变量都是一个指向某种型别的指针变量,它首先是变量,然后是指针变量,再然后是指向某某某型别的指针变量,第四是指向某具体变量的指针变量,被指的变量可以是其它类型,但指针变量都是一个32 int
2,变量的作用域,指针变量只为索引被指代的变量,如果被指代物被释放了,而指针本身没有被释放,就成了野指针.
3,变量的所占的空间,不用说了吧
虽然存在极大的不同,但是,但是指针的精神要求你把它们二者建立"他们是相同的"这样的认识,这是基于抽象的考虑要求的
比如int* pointoaint;????? //pointoaint就是一个关于int类型的指代,,,
那么这种指代有什么用呢,(相比之下,引用比指代更能体验这一点,引用=它所指的对象本身,它所引用的对象本身,虽然这二个概念不等价,但指针这层抽象的意义就是让我们人脑把指针作这样的理解,)
在单根继承OO语言中(就是所有的语言级的first class OO对象都是从一个Tobject这样的东东继续而来,用户定义的OO对象也需要从这个根对象定义而来一样)实现泛编程的容器中,,比如JAVA的LIST中,一般用指向TOBJECTS的引用再填充这个LIST,这样容器里的对象不是对象实体,而是指向他们的索引对象,,,
很显然,JAVA的LIST中的对象都是索引他们的引用变量,而非对象本身,是假对象.
另一方面,,,人们用索引来看待变量的方法,,这种行为自身也表明,,引用只是一种靠近人脑的抽象,,,是一种语言的抽象机制,,人们说指针是C语言的灵魂,,说的就是这个道理..
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

板凳
 楼主| 发表于 2011-10-22 15:37:11 | 只看该作者
4.9 学C千万不能走入的一个误区(其实JAVA比C难)
C语言重点不是为了来开发应用的,,而是为了开发跟计算机本身(远离业务)那一层面的逻辑
C的开发早过时了,,现在是高层逻辑开发时代,,,,
现在的WEB开发,,,提出了一系列新语言,新的框架,,设计哲学,,这些都是远离计算机底层的(比如数据跟算法),,更像是一种逻辑的配置,,然而逻辑的配置比开发更难,,,,这个道理就像:这个时代GUI远远比CUI常见,,但反而CUI才是主流
这就是说,抽象远离了计算机底层,,在高层又变得异常灵活和难于掌握,,
其实JAVA这样的语言因为面向WEB,面向业务,,,它要学习的东西反而更多更难,,,学习JAVA,如果不学WEB,这几乎是件可笑的事情,可是JAVA易学,WEB就不易学了
但是C语言要解决的问题永远是底层,系统永远是简单和形式的,大不了把数结与算法学精.学透,把系统本身学透,,C的开发就到家了
但是JAVA后面的应用问题永远有新的学习需要出现,,因为JAVA后面的东西是异常灵活的高层应用而非固定的底层...面临的问题永远有新的解法,WEB领域永远有新框架新语言的提出..
所以我说,,,其实JAVA比C难..!!!!!
这就跟C一个道理,,C易学,,但C面向的系统问题涉及到大量数据和算法,又显得很难,,,如果学C,却不是为了解决系统,这又是一件可笑的事情,,,永远不要以为学好一门语言就是全部目标了
学好C语言在于将C语言包括指针在内的所有语言机制习惯用法,跟数据结合和算法的结合,,C用于实际问题才是重点要学习的
懂了C,却没懂系统底层一样没有用,不懂数据与算法也没有用,因为C就是面向并开发这些的
其实,JAVA和C都可以发展很多后来的抽象,,JAVA和C 容易学习,是因为它们入口处小,(JAVA和C有有限的语言机制和学习成本)学习和控制就很容易了,,但抽象应该长足发展(WEB问题和系统问题是一个不断可以深入的话题,需要新的语言机制的支持),,JAVA和C解决的问题永远没有一个头,,永远都可以是新的话题..因为应用无形而语言有形
应该相信一些简单的道理,因为它们是道,道统一所有理
无论是什么语言,一门语言写出的程序总是程序=抽象+接口,
(C的抽象在于抽象底层机器因素,提供程序员可见的因素和机制,,这就是抽象,,对于人的靠扰,C的接口在语言级的细微度接口主要还是函数级的接口,,编译器级有.out文件,,,底层=算法加数据..接口提供了功能模块如何交互和复用的机制)
再比如JAVA,,提出了很多语言机制,,也是为了能更好地远离本地发展抽象,,,它把什么都OO化了,这很利于对开发人员的抽象,,,,
它提出的OO,,,一方面既是抽象机制,,,一方面也是接口机制..

4.10 C抽象惯用法
诚然,C只有有限的语言要素,它的语法只是稍微抽象了汇编,它适合描述系统底层,而不适用表达过高的抽象,比如它没有直接站在OO角度上去描述除系统底层问题之外的其它问题,C的那些语法机制是C在语言级能用来表达所有问题的唯一方式(即使这样,C还不失为一种系统编程和应用编程的综合语言,它的表达能力还是巨大的而且C的优点是易于学习进门但进阶难,不像别的语言连进门都难比如OO语言,它的OO机制一时半会是很难被初学者理解的)C虽然没有语言级的OO,不能直接用C的某种语法机制进行OO思维写OO代码,但C的一些简单语法机制同样可以实现模拟了的OO的抽象(作为库级抽象来进行OO)。。这导致“如何用C达成高度抽象语句或程序”这样的问题的产生(不只是OO,C也可以实现C++的template各种各样的抽象来间接解决现实问题而不满足于用C本身来直接解决问题,这里,间接解决现实问题定义OO等库逻辑,就是抽象的意思所在)。
这就是说,抽象并不用C的语法机制直接写应用,而是在进行某种设计,在C模拟的OO中,它企图先在库级完成C模拟的OO,再去解决它要解决的最终问题,当然这只是C抽象的一种,C的抽象主要表现在四个方面,1.用C来解释的数据结构问题本身就是某种抽象和设计,在一些教材讲解到的C版本的数据结构教学中,可以大量看到C写抽象的方式 2,C的指针是C的主要抽象手段(这样说是因为一些其它C的语法要素也跟指针一样用于设计导致高抽象,),C的指针可直接产生很多复杂的思想 3 跟上面一开始谈到的一样,我们想用C构建某种靠近现实问题的抽象,比如我们想用C来实现OO,或者template,这样C的这些逻辑就成了dsl了。再来解决问题。4,我们不想先实现一个OO,template这样的通用解决问题的C抽象,这样的通用抽象称为范式,而是直接面对要解决的问题,用C的语法语言要素去产生一个或一套习惯用法的抽象。相比OO,template这些范式是小规模的抽象惯用法,下面我们来讨论一下C高抽象的习惯用法。。我们还有另一章专门讲解OO范式.
1),,用指针,struct,typedef,,这样的东西可以声明一个链表的结构本质,这在数据结构中大量看出。指针是“通过地址来操作变量”的抽象,struct是建立在简单数据类型上复合数据类型的抽象,typedef是type redefine的抽象。。这些抽象分别使用,或者组合使用可表示很多其它高级抽象。。
2)形参定义为指针,实参向它传地址,实质上是传值然而意义上是传送地址,这种指针的抽象用法,可用来影响调用函数中的实参。
3)void这种类型可作为形参,实现一种多态机制,,void函数也是如此.
4)C语言数组的本质是地址,多行数组是按行优先描述的一维数组,因此其元素地址都可由数组名抽象得到.
5)字符串是一种变长字节,操作字符串的那些函数,也可操作内存块,这就把字符串抽象为一种数据结构的东西。
6)C用void (foo *)(int)这样的结构来表示返回void,以int为参的函数指针foo.这遵守屏看原理.关于函数指针和数组指针还有很多抽象的变形。。来实现回调函数等抽象。
7)C的指针在链表中,实现了一种"指针即变量自身"的指代作用,比如stack->next=stack->next->next,这种指针的赋给,实际上就是指针所指变量在意义上的直接替换。。这也就是C++中为指针新增的引用语法。。
8)typedef实现了换名和子集定义抽象,用旧类型定义出新类型,新类型就是旧类型的别名,或者是旧类型的一个子集,这样的抽象语义。。特别是define实现了一种变量替换式的函数抽象。
9)用const或双层const进行防修改。
10)还有很多很多。。
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

地板
 楼主| 发表于 2011-10-22 15:39:19 | 只看该作者
4.11 C的抽象范式之OOP
其实我觉得C++之父不必把它的c前端版本的C++弄成一个独立的编译器,因为不这样的话,写出来的OO代码也是C的,这样就能极大范围地做到语法上统一,也能将接口保持在C函数的级别供脚本语言使用,而即使在这些模拟中,不少正是直接对应一模一样或几乎一样的C++的本质。无论如何,下面我们讨论一个前端版本的OO模拟,顺便学习一下C++面向对象的内容本质。
先来看看面向对象几种层次抽象
我们知道在C++实现的OO机制中,存在class,class=type,即template中的type,但是我们知道template更像是一种建立在C++类型机制上的脚本语言,其语法古怪,不接近C++本身,,C++用class作为派生type的类型,用type作为template中的类型。
class可用来派生子类型也可用来产生对象(我们用措词上的区别来区分这二者),派生的子类型subclass,此时它也是一个class,,产生的object,我们称一个对象为class的instance.class为object model
这其中存在一些特例,比如纯抽象的class(用来实现C++版本的interface),,或者静态类,,
为了产生逻辑,我们可以继承,也可以组合,继承就是从相对基类中(除了单根继续的语言,基类都是严格相对的)单层继承或多层继续,产生新的类,这样的子类在抽象上继续了父类的所有属性,在底层实现上其实是叠加了子类的代码在基类上的组合代码,是发生在类间的逻辑。也可以由类产生对象以产生逻辑,是发生在类和对象之间的逻辑,,,注意多层继续在现代OO中是不受鼓励的。。
我们将会在下面的RTTI部分讨论以上机制在底层的对应实现。。
而发生在对象之间的逻辑呢,是采用将一个对象作为另一个对象的数据成员来作为产生逻辑的方式,,对象之间交互的方式就称为消息,C开发的函数范式在这里被消息所代替,实际上我们知道消息也是函数调用,只不过这里的函数是加了访问控制和多态的特殊性函数。。
C的模拟OOP主要有以下几个技术,1,用预处理宏定义keyword和定义结构,2,实现rtti.当然,在C++中写多态有三种方式,1,是C++扩展了C的普通多态函数(重载只是多态的简单手段,稍后谈到的2,3才是高级手段),2是OO里面的多态函数,3是模板的泛型多态,,我们只在这里讨论oo里面的东西,,并不打算讨论其它的机制。比如C++所有的3种多态。纯adt的interface机制,也不讨论C++中C没有的异常机制。更不打算讨论templaste。我们只模拟OOP的典型和核心特征。。
首先就class来说,如何模拟呢,

4.12 C的观点:底层不需要直接抽象
抽象是为了简单化,抽象=对机器的简单性=对人的复杂性
C++在语言语法级集成的抽象太多了,而且它的库级抽象也太多了,BOOST,编译期的泛型抽象,运行期的OO泛型抽象等,,OO抽象等,,无一不表示,C++更适合当一门靠近应用的语言(只有高层应用要求抽象,底层开发就要不得太多抽象,因为机器本身就是机器,C就是对应机器的,无抽象必要),,,这造成的结果是要全面掌握C++要求人们掌握的知识太多了,C++的这么多因素使C++变成了多范型,完全密封远离低层(然而你要知道,抽象意味着对底层的迂回,对人类思维的靠扰,这迂回多了,对底层的访问就少了),,,,其实C++也明显没有损耗C操作底层的能力(我这里仅指它OO范型和模板等高级语法机制),,,,但是它提供高级的语言级和库级的抽象反而对人们要求掌握它的成本变得过高了,这就是说,C++对于开发人员提供的"形式,工具"过多(至少比C多).,提出了很多抽象,.在提供的抽象方面,C只有指针,函数指针,结构体,这些有限的东西,而C++呢,有OO,有TEMPLATE(语法级),有STL,有BOOST(库级)这么多
在开发人员这端,C++代码复杂难解,因为一个会读C++源码的人首先要理解语言本身,才能理解作者要想在代码中描述的现实事物(机器逻辑通过C++对于应用逻辑和现实事物的变换),,,而这里面,抽象太多了(甚至过度抽象,过度设计)
用OO表现的现实事物,相对于C用结构和函数表达的现实事物来说,,,后者更接近机器.C本身的那么有限的语法机制,即使离开了语法级的OO,C也可直接用函数级的第一类型(组成的模块)和结构体数据抽象,和指针,,这些东西描述应用领域,比如Windows用C表达消息,,jxta用c表达管道,端点这些概念,,,
语言的选择永远离不开应用,要开发底层,,C比C++好,WEB开发是那些远离底层的逻辑,用JAVA可以,但是C其实也是OO的,它的结构体,本身就是一种数据抽象,比如我要描述一个学生,我就选择性的定义一个struct student,里面加上学分啊,身高啊这些数据,(这是最好的方法,比C++的类都要好,为什么呢,因为C语言的类型机制就是计算机的类型机制,,这些定义数据抽象做到了机器跟应用域事物的一一对应,非常地好)
而定义关于数据的抽象是冯氏语言模型的根本,我们知道可以用设计数据的方式抽象DSL概念词汇,系统编程支持词汇。
JAVA明显不好用来开发底端,,这就是语言适配应用的道理,,但是计算机终久是计算机,如果你想学习计算机本身而不仅仅是想通过掌握JAVA开发WEB,那么C+LINUX永远是最好的选择,因为开源的东西一般出现在LINUX下.而且通常用C开发的,世界上开源项目最多的就是C了.
一句话,C比C++简单,如果想开发图形啊,网络啊,这些跟计算机本身有关的东西,这样的一个想靠掌握语言马上编程的初学者最好去学习C,而不是C++

4.13 指针:间接操作者
type*
这个形式就表示一种类型,,,,如果说type本身也是一种类型的话,那么在type后加一个星号也表示一种类型,,这种类型叫“指向这种type的指针类型(重要的是最后的指针类型这四个字)”,,你可以联想dephi中的ptype类型
所以你就可以这样定义东西
type* someobj;
(*可向type靠近或someobj靠近,C程序员偏向于向someobj而C++程序员偏向于向type靠近,这样的话就有二种等价意义,type *someobj表示*someobj是一种type变量,type* someobj表示someobj是一个指向type的指针)
someobj就是一个指针变量,它代表指向此type的的指针变量,,因此在这里type*是类型(是一种指针意义上的数据类型),someobj是这种类型的一个变量
根本上引用只是一个指针的别名,因此你可以由一个指针得到一个或多个引用(即关于该指针指向的对象的引用)
指针本质上是一个32位long int(因此在Generic progamming领域有“用整型代替类型”的说法),定义一个指针时可定义void*型指针(因为指针并不一定出生时就要指向一个对象或一块内存,而引用要求有一个初始值,因为引用本质是指针的别名),因此它可以被指定为0,即空指针,也可以被重新赋值(此时它就不指向它原来指向的对象或内存了),,换言之,,多个指针可以同时指向一个对象,你可以为一个对象定义多个指向它的指针(但是它并不拥有这一内存,也就是说,当它指向的对象发生了变化,指针仅仅作为指向这个对象在内存中的位置的意义就会失效或过时,它只拥有对象的adress值而非value值),而你可以通过这些指针或引用来操作该对象
一般来说,引用常常跟const在一起(加上const只是为了强制跟保险),那是因为定义出来的引用常常不会改变
type*
这个形式就表示一种类型,,,,如果说type本身也是一种类型的话,那么在type后加一个星号也表示一种类型,,这种类型叫“指向这种type的指针类型(重要的是最后的指针类型这四个字)”,,你可以联想dephi中的ptype类型
所以你就可以这样定义东西
type* someobj;
(*可向type靠近或someobj靠近,C程序员偏向于向someobj而C++程序员偏向于向type靠近,这样的话就有二种等价意义,type *someobj表示*someobj是一种type变量,type* someobj表示someobj是一个指向type的指针)
someobj就是一个指针变量,它代表指向此type的的指针变量,,因此在这里type*是类型(是一种指针意义上的数据类型),someobj是这种类型的一个变量
根本上引用只是一个指针的别名,因此你可以由一个指针得到一个或多个引用(即关于该指针指向的对象的引用)
指针本质上是一个32位long int,定义一个指针时可定义void*型指针(因为指针并不一定出生时就要指向一个对象或一块内存,而引用要求有一个初始值,因为引用本质是指针的别名),因此它可以被指定为0,即空指针,也可以被重新赋值(此时它就不指向它原来指向的对象或内存了),,换言之,,多个指针可以同时指向一个对象,你可以为一个对象定义多个指向它的指针(但是它并不拥有这一内存,也就是说,当它指向的对象发生了变化,指针仅仅作为指向这个对象在内存中的位置的意义就会失效或过时,它只拥有对象的adress值而非value值),而你可以通过这些指针或引用来操作该对象
一般来说,引用常常跟const在一起(加上const只是为了强制跟保险),那是因为定义出来的引用常常不会改变

4.14 真正的typedef
typedef是类型替代名(typedef=type dfine嘛),在理解时可以按以下的方法进行
1.typedef是定义一种类型的子集,,,比如typedef int INT;(这意思就是说,INT是int的一个子集)
2.类extern的这样一种声明(也即仅仅是对类型的向外的一种再声明),如extern int myint;(这意思就是说,作为变量的myint这里作为一种“新的类型”,而且是一种“int类型”,,,这是一种当已有类型的再声明)
也即,extern就是相对于变量,typedef就相对于类型(注意它们二者并不实际等价,也即不会有myint这个实际变量被声明出来)
注意,一般myint要大写,但是这里为了说明还是采用它的小写形式
由第二种理解方式可以导出很多,如typedef int (*myint)(),,,可理解为extern int (*myint)(),,这里的myint也是一种类型,这种类型表示“指向一个返回int类型的函数的指针类型”

4.15 真正的指针类型
type*
这个形式就表示一种类型,,,,如果说type本身也是一种类型的话,那么在type后加一个星号也表示一种类型,,这种类型叫“指向这种type的指针类型(重要的是最后的指针类型这四个字)”,,你可以联想dephi中的ptype类型
所以你就可以这样定义东西
type* someobj;
(*可向type靠近或someobj靠近,C程序员偏向于向someobj而C++程序员偏向于向type靠近,这样的话就有二种等价意义,type *someobj表示*someobj是一种type变量,type* someobj表示someobj是一个指向type的指针)
someobj就是一个指针变量,它代表指向此type的的指针变量,,因此在这里type*是类型(是一种指针意义上的数据类型),someobj是这种类型的一个变量
根本上引用只是一个指针的别名,因此你可以由一个指针得到一个或多个引用(即关于该指针指向的对象的引用)
指针本质上是一个32位long int(因此在Generic progamming领域有“用整型代替类型”的说法),定义一个指针时可定义void*型指针(因为指针并不一定出生时就要指向一个对象或一块内存,而引用要求有一个初始值,因为引用本质是指针的别名),因此它可以被指定为0,即空指针,也可以被重新赋值(此时它就不指向它原来指向的对象或内存了),,换言之,,多个指针可以同时指向一个对象,你可以为一个对象定义多个指向它的指针(但是它并不拥有这一内存,也就是说,当它指向的对象发生了变化,指针仅仅作为指向这个对象在内存中的位置的意义就会失效或过时,它只拥有对象的adress值而非value值),而你可以通过这些指针或引用来操作该对象
一般来说,引用常常跟const在一起(加上const只是为了强制跟保险),那是因为定义出来的引用常常不会改变
type*
这个形式就表示一种类型,,,,如果说type本身也是一种类型的话,那么在type后加一个星号也表示一种类型,,这种类型叫“指向这种type的指针类型(重要的是最后的指针类型这四个字)”,,你可以联想dephi中的ptype类型
所以你就可以这样定义东西
type* someobj;
(*可向type靠近或someobj靠近,C程序员偏向于向someobj而C++程序员偏向于向type靠近,这样的话就有二种等价意义,type *someobj表示*someobj是一种type变量,type* someobj表示someobj是一个指向type的指针)
someobj就是一个指针变量,它代表指向此type的的指针变量,,因此在这里type*是类型(是一种指针意义上的数据类型),someobj是这种类型的一个变量
根本上引用只是一个指针的别名,因此你可以由一个指针得到一个或多个引用(即关于该指针指向的对象的引用)
指针本质上是一个32位long int,定义一个指针时可定义void*型指针(因为指针并不一定出生时就要指向一个对象或一块内存,而引用要求有一个初始值,因为引用本质是指针的别名),因此它可以被指定为0,即空指针,也可以被重新赋值(此时它就不指向它原来指向的对象或内存了),,换言之,,多个指针可以同时指向一个对象,你可以为一个对象定义多个指向它的指针(但是它并不拥有这一内存,也就是说,当它指向的对象发生了变化,指针仅仅作为指向这个对象在内存中的位置的意义就会失效或过时,它只拥有对象的adress值而非value值),而你可以通过这些指针或引用来操作该对象
一般来说,引用常常跟const在一起(加上const只是为了强制跟保险),那是因为定义出来的引用常常不会改变

4.16 真正的函数指针
C和C++都不允许一个真正的函数作为参数,,将函数作为参数传送的办法是将它用一个指针去指向这个函数,,,,
而且,通过函数指针和函数模板,可以很有效地实现业务逻辑跟界面逻辑分开
学习函数指针完全是一种挑战,你能分别出以下的吗?
int *(*(*foo)(int))[5];
这个就表示:foo是一个函数指针(这就是括号带星号的结果-即把*foo括起来的那个括号),它指向一个函数(以指向它的指针foo命名的函数),它带一个int参数(即函数指针foo紧靠右的那个括号和括号内的int),,并返回一个指向数组的指针
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

5#
 楼主| 发表于 2011-10-22 15:41:12 | 只看该作者
4.17 真正的句柄
句柄一般有三种意思
1,Window的资源句柄
一个语言跟操作系统的关系是什么??
一个操作系统可以用一种语言写成,,因此如果语言出现在前(历史原因),那么操系统(或其一个小节)会用这种语言来描述,,,比如Windows的对象,,就是说如果Windows是用C++来实现的,那么这个对象就是CUI(**—对象
根本历史,,一方用另一方的东东来描述的关系
比如文件,,操作系统普通把文件作为硬盘上的东西,,可是文件在语言的观点里根本就不是这么一回事,,,文件只是data flow,,或者一个file map(也即在内存中作引象),,,,

2,包装被指对象为其值的智能指针
3,形如type**的双层指针
4,其实通用意义上的Handle就是句柄的意思,句柄还有一种用处出现在编译原理中
5,如下
如果B是A的一个子类,,,有如下代码
(A)new B
那么以上可以理解为,,,上面产生了一个对象,,这个对象指向B(指针),,,但是其句柄为A
即a handle of A pointing
to a B,
也即第四种指针是用父类来操作其子类对象的一种机制

4.18 真正的循环
for的条件表达式可能短路,,它的update部分可以是任何算式,甚至不要updata部分
一般把最常发生case的情况放在最后面,如果你学过汇编就知道,编译器是从后到前搜索的
注意汇编是没有逻辑运算符的,只有移位运算符(而往往C++中把它们同用)
有三种,,逻辑(与,或,异或,取反),移位(无符号左移,,右移,,高位补0等等),
在汇编中
contine和break的区别,contiune放在循环语句的某一具体层中,当满足条件时,继续执行下一个当前循环(即重新判断条件),而break可以放在一个循环的任何地方,是跳出当前循环(注意因为循环可能是嵌套的,所以这个当前循环是指break所在的那一个嵌套层次),,然后继续执行这个循环外的第一条语句(即结束循环)。

4.19 真正的static
在C++中,一个结构也有它的构造函数,这个构造函数(接口类不应包含构造函数)往往作为初始化该结构的初值使用,因此一般将它们作为static来定义,这就不得不说说static到底给语言增加了什么?
static的成员也不是静态的,它也可以进行自加自减这样的操作,
static是在编译期发生的,因此不能在运行期改变它
在一个函数体内定义的static数据,,相对整个程序来说都是全局的(直到被销毁)
因此static提供了一种把局部自动变量转化为暂时全局性的东东,,比如对于一个在函数体内的常量来说
static也被作为类级的私有成员数据或行为(类属函数),因为类只是定义对象的规范,因此它应该没有一块内存实际存在用于调用它的成员(一般方法是具体化出它的一个对象然后调用对象在类中定义的成员),但是static提供了一种“全局静态”的概念(类级的全局),比如Java中systme名字空间的API就是全局的API(包级的全局),可以直接拿来用
函数退出这个常量就失效了,解决的方法是用static或const
static的作用就在于“保值”时空限度为定义它的整个模块,,这是相对静态局部变量来说的,,还有静态全局变量
要注意,一个函数的原型和它的具体实现是分开的,你可以overroad(复写)一个基类的private的函数声明,但却不能调用它的实现
也即,只能复写声明,而不能调用定义(实现)
在C和C++中,声明和定义是分开的,如int i=9;就是一种定义(因为连初值都赋过了这说明分配了内存),而extern int i;只是一种声明而已(向外界宣告它的存在),而Java中就没有声明跟定义的差别了。上面是对于变量来说的(特别是对动态对象—也即对象变量这种表现更加明显),,对于函数的声明和定义的区别就更加明显了。

4.20 真正的数组索引
指针经常跟数组在一起,因此它也经常跟索引相关
因为字符串也是一个数组(更准确来说是可以用数组来实现的线性表,只不过它的最后一个字符是/0而已),所以形如char*的字符串也一定跟数组有关
如果一个指针指向一个new type[num]形式开辟的数组,那么经常有下面的形式出现,
数组名=指针=数组的索引1的地址=用双引号括起来的一串字符串
char* myvar = “iloveu”是用字符指针指向字符串第一个字符在内存中的位置,char[] myvar2=”iloveu2”也是成立的(字符串往往以字符指针或这种字符数组来表达)。
指针加1等价于索引也加1,但是这其中发生的本质是不一样的,,指针值加了sizeof(type)的值,,而索引只是向后一个索引递进而已
指针只能在堆上存在,,,而不能在一个函数的栈帧上存在,alloca可在一个栈上声明
“同一”与“等价”的区别就在这里出现了
实际上数组的地址的确等于它的第一个元素的地址,,然而数组的地址并不是它的第一个元素的地址,而是这个完整数组的地址开头
mfc的消息机制就是一种表驱动

4.21 类型和屏看原理
BCPL作为C语言的始祖(就连32位汇编语言都引进了变量和类型,类型是一门语言的基础,用来表示为程序所用的内存的抽象,即多少内存,可以在这个类型上执行什么操作),它是没有数据类型的,实际上一切都是抽象,C语言中的基本类型正是抽象了“以何种方式使用内存(更确切地说是使用内存的位,因为这是汇编语言和机器逻辑最终要考虑的问题,在高级语言中得抽象一下不能直接用位组)”,使用内存的方式就成了基本类型,这是一种抽象。。将基本类型发展为Struct聚合类型又是一种抽象,,将数据类型封装为ADT(同时封装了可施加其上的操作)就更是一种抽象了。。基本类型中为什么会有数值,字符就知道了,这完全是一种趋向现实的抽象,这是每一种语言的每一个程序,每一个现实问题最能广泛体现到的抽象,当然,基本类型完全也可以是函数,如Lisp语言,,只要是一门语言直接支持的类型,那么它必定在内存中有一个位存储模式,汇编器规定了什么样的操作可以施加在这个位组合上。,
要深克地理解C语言中的“屏看”原理,比如下面二个例子
void (int *p1,int *p2)
#define mysub(x) x^3/x
在第一句中,参数是p1,而不是int,即不是*p1,我们优先看到p1,p2这样的变量,即参数是变量
在第二句中,define的是mysub(x)这个整体,而不是x,我们优先看到mysub(x),即define语句的整个前半部分
一些名理:
命令行就是观念里自由的世界(编程时从观念里出来,去除表现逻辑和其它逻辑,就事论事,不必输出到gui上,只直接面向输入输出到标准,这些语言级而非应用逻辑级的东西),GUI就是强加了面具做人的不自由
能图灵处理的问题,就是计算机能解决得了的问题,可通过程序手段反映出来。
我们称最小接口为原子操作,因为由它们可以演化得到更高级的接口。
一个源程序模块或二进制模式能运行,一定同时包含了指导CPU的指令和待处理在内存中的数据。。
解释器就是直接运行中间码,不需要完成到目标码的转换。。在编译前端,它还是比较跟编译器一样的。。

4.22 位操作与多维数组指针与元素
首先C语言提供位一级的操作是为了迎合汇编语言,,回忆一下CPU的指令集,,有专门的位操作指令,C只是稍稍地将它们进行了下抽象(这样的话,C有了位操作再加上指针,它就成为系统和控制语言了,抽象不但隔断不必要的细节,而且在另一层维度上,提供了对于人来说更为强大的功能,这就是抽象的二大特征),对比一下我们就知道它们的差别并不大,,CPU还有OF,和CF这二个寄存器来表示移位和运算时发生的进位和溢出现象。。
我们知道,在存储位的时候(更确切地说是一个字节级的东西),Intel的CPU是按高位在前(书写或打印时显示在左),低位在后存储的(在右)。因此位往左边移的时候(因为左边是高位,位到了左边就占了一个高分位,整个二进制会按基数越来越大),就是乘以2的幂,体现在它的十位制表示会越来越大,C语言规定,一个类型的值向左移位的时候(右边会溢出不用),在它的右边低位加0,一直补满这个类型应有的位数。。而这个值向右移位的时候,位到了低分位,整个二进制按基数2越来越小,,移了几次位就相当于除以2的几次幂。。移位的时候,左边补0,如果原数左边是0,是个正数,那么还是补0,如果原数左边本来是1,是个负数,那么根据不同的编译器会采取不同的动作,有的编译器把它看成“简单算术右移”,最左边那个位还是补1,有的编译器会把它看成“逻辑右移”,,会把最左边空出来的位加0..
有人会问了,移位会不会把周围内存的位给挤了,不会的,因为所有的移位操作,只局限于这个类型的这个值,跟内存中其它值(只要它们都不参与此次位移运算)都没有关系。。如果二个不同类型的值用一个二目移位符连接时,编译器会进行对齐操作以使它们有相同的位数。。
位定义了几种运算符,有与(实际上不是逻辑乘,但我们按乘的原理可以得出它的计算方式),或(逻辑加),异或,取反,各种运算用在不同的目的下,与可以用一个屏蔽字屏蔽给定值特定位,就是把它们置0,,,,或可以用一个屏蔽字屏蔽给定值特定位,,就是用1去保留它们。。异或可s以反转特定位。。
这样所有的工作就成了找一个需要的屏蔽字(根据原值,,面向要作什么样的屏蔽要求,这二个因素)。。
在单维数组中,,指针跟"&数组名[索引]"或"数组名+索引"的方式有点相似,,实际上这是C语言语义的二义性,,这是为了让C语言变得灵活而保留的。。而在多维数组中,&数组名[索引]"或"数组名+索引"往往并不是一回事。。这一切都是因为C语言中的多维数组其本质还是单维数组,,因此用单维数组的索引或指针方式用在多维中,就会出现很多语义。。
我们来分析一下,可以得出以下结论:
首先,我们知道数组名并非指针,它只是一个意义上的等同,实际上存在数组名作为指针,,但是不存在"&数组名[索引]"这样的元素,,它表示一个地址(从...开始的地址)而非表示一个元素。。尤其是在多维数组中要分明白。。

4.23 变量与VOID
C语言中有一种void类型,,无类型指针。。我们知道变量是有三个要素的,1变量的名字,2,变量的地址,3,变量的类型,其中3是最重要的,它影响了2,,这也就是说,对于一种变量来说,一谈到这种变量,它的大小就清淅了,,变量的最重要的特性是它类型影响下的大小。。。这是变量的本质
所以,对于变量的指针这种类型来说,,在使用它之前,一定要知道这指针是指向什么变量,,这样编译器才知道从这个地址,以多少大小的范围去操作它,否则void类型的指针是不能被解引用的,只能供调用参数用。。
使用void来作为函数参数时,主要出于这种目的,比如我们想让一个函数处理多型数据,就可传递这种数据的指针,因为是多型,我们不直接定义int *,float *,这样多的类型,而代于void作参,这样处理时带来void解引用后的结果(当然,得cast成int*或float*这样实际的指针变量才能使用得到它指向的数据)。
而cast是一种什么样的过程呢,C语言的隐式转换是编译器的动作,手动转换是程序员的事,但是,无论是这二转换的那一种,都不改变原指针值,它只是在内部作了一份拷贝(这个道理就像传指针也是传值,不过传的是指针值,因此另外一种意义上来说就相当于传地址,,它跟直接传值一样,也是作一份拷贝),你可以将这个拷贝值看成为C++新增的指针语法:变量别名。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

     
    Archiver|手机版|小黑屋|( 沪ICP备12034951号 )

GMT+8, 2024-4-28 19:01 , Processed in 0.119344 second(s), 30 queries .

© 2001-2011 Powered by Discuz! X3.1

快速回复 返回顶部 返回列表