您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 交通运输 > C语言深度剖析读书笔记
1、定义:所谓定义就是(编译器)创建一个对象,为这个对象分配一块内存并取上一个名字,这个名字就是我们经常说的变量名或对象名。一个变量在一定的区域(比如函数内,全局等)只能定义一次。2、声明:(1)告诉编译器,这个名字已经匹配到令一块内存上了,下面的代码所用到的变量或对象是别的地方定义的。(2)告诉编译器,这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名。3、定义和声明的区别:定义创建了对象并为这个对象分配了内存,声明并没有分配内存。4、Register修饰符的限制:register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且register变量可能不存放在内存中,所以不能用取地址运算符“&”来获取register变量地址。5、Static的作用:(1)修饰全局变量:静态全局变量的作用域仅限于变量被定义的文件中,其它文件中即使用extern声明也没办法使用它。准确的说作用域是从定义之处开始,到文件结尾处结束,在定义之前的那些代码页不能使用它,要想使用,就要要在前面加extern***。要避免这种问题,直接在文件顶端定义就行了。(修饰全局变量,实际上是改变了该变量的链接属性)(2)修饰局部变量:静态局部变量,在函数体内定义的,就只能在这个函数里使用了,同一个文件中的其它函数也用不了。由于被static修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量也不会被销毁,函数下次使用时仍然能使用到这个值。(修饰局部变量时,实际上是修改了该变量的存储属性)(3)修饰函数:函数前加static使得函数成为静态函数。该函数的作用域被局限在本文件中(又成为内部函数)。(修饰函数时,实际上是修改了该函数的链接属性)6、数据类型:数据类型的作用就像大小不同的模子,在内存上根据模子的大小(类型)刻出固定大小(类型)的一块块内存。7、变量的命名规则:(1)较长的单词,去掉“元音”形成缩写。(2)标识符由多个单词构成时,每个单词的第一个字母大写,其余全小写。(3)尽量避免名字中出现数字编号,除非逻辑上的确实需要编号。如驱动开发时为管脚命名,非编号名字反而不好。(4)多个文件之间共同使用全局变量或函数要加范围限定符(建议使用模块名(缩写)作为范围限定符)。(GUI_,etc)(5)含义标志命名规则,变量名使用名词数组,函数名使用动词数组(6)程序中不得出现仅靠大小写区分的相似的标识符。(7)一个函数名禁止被用于其它之处。(8)所以宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。(9)考虑到习惯问题,局部变量中可采用通用的命名方式,仅限于n,i,j等作为循环变量使用。一般说,习惯上用n,m,i,j,k等作为int类型变量;c,ch等作为字符型变量;a等表示数组;p等表示指针。当然这仅仅是一般习惯,除了使用i,j,k等可以用来表示循环变量外,别的字符变量名尽量不要使用。(10)定义变量的时候不要忘了初始化。定义变量时编译器并不一定清空了这块内存,它的值可能是无效数据。(11)不同类型的数据之间运算要注意精度扩展问题,一般低精度向高精度数据扩展。8、sizeof:sizeof是关键字,而不是函数。Sizeof在计算变量所占的内存空间大小时,括号可以省略,而计算类型(模子)大小时不能被省略。一般情况下不要省略,加上括号,继续当做一个“函数”来使用。9、计算机中数据存储:计算机系统中,数值一律用补码来表示(存储)。主要原因是使用补码,可以将符号位和其它位统一处理;同时,减法也可以按加法来处理。另外,两个用补码表示的数相加时,如果最高位(符号位)有进位(向符号位的进位?),则进位被舍弃。正数的补码与其原码一致;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1。(-1的补码为0xff)10、Bool变量与“零值”进行比较:不要写成if(bFlag==0),会给人一种bFlag是整型的感觉。写成if(bFlag==FALSE);或者写成if(bFlag==TRUE),也不好。因为,FALSE的值在编译器中被定义为0;但TRUE在VisualC++中定义为1,而在VisualBasic中TRUE定义为-1。而写成if(bFlag);或者if(!bFlag);就比较好,该种写法既不会引起误会,也不会由于TRUE或者FALSE的不同定义值而出错。以后写代码就要这样写。11、Float变量与“零值”进行比较:不能写成if(fVal==0.0),要写成if((fVal=-EPSINON)&&(fVal=EPSINON));//EPSINON为定义好的精度12、指针变量与“零值”进行比较定义指针:int*p=NULL;//定义指针一定要初始化写成if(p==0)或者if(p!=0),这样不好,给人一种p是整型的感觉写成if(p)或者if(!p),这样也不好,给人一种p是布尔型的感觉写成if(NULL==p)或者if(NULL!=P),这样比较好,把NULL写在前面是为了避免少写个“=”时,编译器会提示错误。13、if语句有的分号:if();后的分号常常会由于误加而造成编译器检查不出的错误,如果if()后确实需要一个空语句,写成NULL;比较好。14、每个case语句的结尾绝对不要忘了加break,否则将导致多个分支重叠(除非是有意使用多个分支重叠)。15、最后必须使用default分支。即使程序真的不需要default处理,也应该保留语句:default:break;这样做不是画蛇添足,可以避免让人误认为你忘了default处理。16、case关键字后面的值的要求:case后面只能是整型或者字符型的常量或者表达式。17、case语句的排列顺序:正常情况放在前面,而把异常情况放在后面。如果有多个正常情况和异常情况,把正常情况放在前面,并做好注释;把异常情况放在后面,同样要做注释。18、break和continue的区别:break关键字很重要,表示终止本层循环。Continue表示终止本次循环,进入下一轮循环。19、在多重循环中,如果有可能,应将最长的循环放在最内层,最短的循环放在最外层,减少CPU跨切循环层的次数,从而提高效率。20、不能再循环体内修改循环变量,防止循环失控。例如:For(n=0;n10;n++){……n=8;//不可,可能违背了你的意愿}21、一般不要使用goto关键字:一般来说,编码的水平与goto语句使用的次数成反比。由于goto语句可以灵活的跳转,如果不加限制,它的确会破坏结构化设计风格;其次,goto语句经常带来错误或者隐患。它可能跳过了变量的初始化、重要的计算语句。所以,一般不要使用goto语句,乃至禁用。22、void关键字:void的字面意思是“空类型”,void*则为“空类型指针”,void*可以指向任何类型的数据。void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量。事实上,如果定义如下:voida;编译会报错,即使不报错,它也没有任何实际意义。void真正发挥作用在于:(1)对函数返回的限定(2)对函数参数的限定众所周知,如果指针p1和p2的类型相同,那么我们可以把平p1和p2相互赋值,如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换成左边的指针类型。而void*则不同,任何类型的指针都可以直接赋值给它,无需强制类型转换,如:void*P1;int*p2;p1=p2;但这不意味着,void*也可以无需强制类型转换地赋给其它类型的指针。因为“空类型”可以包容“有类型”,但“有类型”并不能包容“空类型”。所以,下面的语句编译会报错,P2=p1;//把空类型赋给了int型23、如果函数没有返回值,则应该声明为void类型,在C语言中,凡是不加返回类型的函数,就被编译器作为返回整型值处理。24、如果函数无参数,应该声明其参数为void。在C语言中,可以给无参数函数传送任意类型的参数,但在c++中,函数参数为void的意思是这个函数不接受任何参数。如果在调用这个函数的时候,是有参数的,那么编译器会报错。无论在C还是在C++中,若函数不接受任何参数,一定要声明参数为void。25、ANSI(AmericanNationalStandardsInstitute)标准,不能对void指针进行算法操作,即一下操作都是不合法的:void*pvoid;pvoid++;//ANSI:错误pvoid+=1;//ANSI:错误ANSI标准之所以这样认定,是因为它坚持:进行算法操作指针必须是确定知道其指向数据类型大小的。例如:int*pint;pint++;//ANSI:正确但是在大名鼎鼎的GNU(GNU’sNotUnix)则不这么认定,它指定void*的算法操作与char*一致。因此,void*pvoid;pvoid++;//GNU:正确pvoid+=1;//GNU:正确在实际程序设计中,为了增强可移植性,可以这样编写:void*pvoid;(char*)pvoid++;//ANSI:正确;GNU:正确(char*)pvoid+=1;//ANSI:正确;GNU:正确26、void不能代表一个真是的变量:因为定义变量时要必须分配内存空间,定义void类型变量,编译器到底分配多大的内存呢。下面的代码企图让void代表一个真是的变量,因此都是错误的:voida;//错误function(voida);//错误void的出现只是为了一种抽象的需要,如果你正确的理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。正如不能给抽象基类定义一个实例,我们也不能定义一个void(让我们类比的成void为“抽象数据类型”)变量。27、return关键字:return用来终止一个函数,并返回其后面跟着的值。Return(Val);//此括号可以省略。但是一般不省略,尤其是在返回一个表达式的值时。28、return语句不能返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁。例如:char*Func(void){charstr[30];returnstr;}str属于局部变量,位于栈内存中,在Func结束的时候被释放,所以,返回str将导致错误。29、const关键字:const是constant的缩写,是恒定不变的意思,也翻译为常量、常数等。所以,很多人认为const修饰的值是常量。这是不准确的,精确的说,应该是只读变量,其值在编译时不能被使用,因为编译器在编译时不知道其存储内容。或许当初这个关键字应该被替换为readonly。Const推出的初始目,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。(1)定义const只读变量,具有不可变性。例如;constintMax=100;intArray[Max];在VisualC++6.0中分别创建.c文件和.cpp文件测试。.c文件中编译会报错,而在.cpp文件中则顺利进行。为什么呢?我们知道定义一个数组必须指定其元素个数。这也从侧面正是了C语言中,const修饰的Max仍然是变量,只不过是只读属性罢了;而在C++中,扩展了const的含义,这里不再讨论。(2)const修饰的变量必须在定义的同时初始化。(3)节省空间,避免不必要的内存分配,同时提高效率编译器通常不为普通的const只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。例如:#defineM3//宏常量constintN=5;//此时并未将N放入内存中……inti=N;//此时为N分配内存,以后不再分配intI=M;//预编译期间进行宏替换,分配内存intj=N;//没有分配内存intJ=M;//再进行宏替换,又一次分配内存const与#define的区别:(a)const定义的只读变量从汇编角度来看,只是给出了对应的内存地址,而不是像#def
本文标题:C语言深度剖析读书笔记
链接地址:https://www.777doc.com/doc-4813870 .html