《C陷阱与缺陷》读书笔记与总结
《C陷阱与缺陷》读书笔记
目录
- 《C陷阱与缺陷》读书笔记
- 一,函数指针和指针函数
- 二,C语言数组
- 三,空指针并非空字符串
- 四,整数溢出
- 五,为main函数提供返回值
- 六,声明和定义(extern)
- 七,命名冲突与 static修饰符
- 八,形参、实参和返回值
- 九, 检查外部变量类型
- 十,预处理器-不能忽视宏定义中的空格
- 十一,预处理器-宏不是函数
- 十二,宏不是类型定义
- 十三,比较时把常量写在左边
一,函数指针和指针函数
float *g() , (*h)();
()的优先级大于 * , 因此 *g() 为 *( g() ) ,该函数 g() 的返回类型为指向浮点数的指针 float * 。
而h是一个函数指针,返回值类型为 float。
二,C语言数组
- C语言中只有一维数组,数组的大小需在编译时期确定(常数)数组的元素可以是任意类型的对象(包括数组)
- 对于一个数组,只能做两件事:1,确定数组的大小。2,获得下标为0的元素的指针。
以数组下标进行运算,实际上都是通过指针进行的。
三,空指针并非空字符串
#define NULL 0
当常数0被转换为指针使用时,这个指针绝对不能被解除引用(dereference),换言之,当我们将0赋值给一个指针变量时,绝对不能使用该指针所指向的内存中的存储内容。
四,整数溢出
无符号数无溢出
if((unsigned)a) + (unsigned)b > INT_MAX)
五,为main函数提供返回值
main函数与其他任何函数一样,若未显式声明返回类型,则默认为整型。
六,声明和定义(extern)
int a;
如果出现在所有函数体之外,则称为外部对象a的定义。a是一个外部整型变量,同时为a分配了存储空间,默认为0;
int a = 7;
在定义a的同时也为a明确指定了初始值。
extern int a; //这是一种引用,而非定义
a是一个外部整型变量,extern说明a的存储空间是在程序的其他地方分配的,只是一个外部对象的显式引用。
如果一个程序包含了 extern int a ,那么这个程序就必须在别的某个地方包括: int a; 那么这两个语句既可以在同一个源文件中,也可以位于程序的不同源文件之中。
七,命名冲突与 static修饰符
两个具有相同名称的外部对象,实际上代表同一个对象,如在两个不同的源文件都包括了定义:int a;
则或表示程序错误(禁止外部变量重复定义),或在两个源文件中共享a的同一个实例。
static 修饰符能解决命名冲突问题:
static int a;
static 具有文件作用域,将a的作用域限制在当前源文件中,对其他源文件,a并不可见。
static同样可以修饰函数,建议:若一个函数仅被同一个源文件中的其他函数调用,我们应当声明该函数为static。
八,形参、实参和返回值
任何C函数都有一个形参列表,列表中的每个参数都是一个变量,改变量在函数的调用过程中被初始化。
任何C函数都有自己的返回值:void/其他
如果一个函数在定义域之前被调用,那么它的返回值默认为 整型
- 如果一个函数在被定义或声明之前被调用,那么他的返回值类型默认为整型。
- 在多文件中,若函数的定义和调用位于不同的文件中,则需要在调用前声明。
九, 检查外部变量类型
外部变量的定义和声明必须保持一致。
比如有两个文件,其中f2.c中定义了一个 long类型的变量n,但是在f1.c文件中却声明为int类型:
- f1.c: extern int n;
- f2.c:long n;
十,预处理器-不能忽视宏定义中的空格
如下所示为ref.h文件中定义的宏:
#ifndef _REF_H
#define _REF_H#define F(x) (x+1)
#define G (x) (x+1) #endif
在main函数中使用:
int a = F(2);int b = G(3);
在使用 G(x)宏定义时出现如下错误:
错误原因在于G和 (x)之间多了一个空格,导致编译器将G作为一个宏,而不是G(x).
十一,预处理器-宏不是函数
注意:
- 要把每个参数都用括号括起来
- 整个表达式也要括起来
#define ABS1(a) ((a) > 0 ? (a) : -(a))
#define ABS2(a) (a > 0 ? a : -a)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
如上代码片段中的两个宏定义所示,在宏定义ABS2(a)中,每个参数不用括号保护,当a=x-y的情况下,直接使用字符替换就会发生错误:
int x = 4;int y = 6;int z1 = ABS1(x-y);int z2 = ABS2(x-y);
根据字符串简单替换的规则:
z1 = ABS1(x-y) = ((x-y) > 0 ? (x-y) : -(x-y)) = -2 > 0 ? -2 : 2 = 2
z2 = ABS2(x-y) = (x-y > 0 ? x-y : -x-y ) = -2 > 0 ? -2 : -4-6 = -10
所以使用括号来保护表达式,是很有必要的。
此外,还要确保宏中的参数不会出现二次变化(没有副作用),如以下代码片段:
int i = 0, arr = [2,4,6,8];
int a = MAX(arr[i++],1);
按照一般思维:i是先使用后自加,所以arr[i++]为2,MAX(2,1)结果等于2,即a等于2。
但是按照宏的简单字符串替换原则:
int a = MAX(arr[i++],1) = arr[i++] > 1 ? arr[i++] : 1 ;
当执行完 arr[i++] > 1 操作后, 还会执行 ? 后面的 arr[i++],此时i等于1,导致a的结果等于4;
最后还需注意的是 宏的嵌套,可能会产生非常庞大的表达式,始终要记住宏是简单的字符替换,而不是函数,C语言中函数可以使用递归(利用了栈的原理)来达到精简代码的目的,如以下代码:
MAX(a,MAX(b,MAX(c,d)));
将其展开后,程序将非常臃肿,不利于后期调试。
总而言之,宏是一种 以空间换时间 的一中策略,在这一点上,类似内联函数。
十二,宏不是类型定义
类型定义可以使用 typedef:
// 宏定义和typedef 一致
#define FOOTYPE struct foo
typedef struct foo FOOTYPE// T1和T2所表示的类型有可能会不一致
#define T2 struct foo *
typedef strcut foo * T1//比如
T1 a , b; // struct foo * a,b; a是指针类型,b是结构体类型
T2 a , b; // strcut foo * a, strcut foo *b; a和b都是指针类型
十三,比较时把常量写在左边
比如:
if( 'c' == a)
{// 推荐这种写法,当少写一个等于号=时,('c' = a)编译器会立即报错
}if( a == 'c')
{// 当少写一个等于号=时,(a = 'c')编译器不会报错,增加了调试难度
}
如上述程序所示,一个鲁棒性高,稳定性高的程序,一定要注意一个原则:
编译时报错 > 运行时报错
也就是说,程序中的bug要早发现早解决,程序运行过程中出现的bug其查找难度倍增。
《C陷阱与缺陷》读书笔记与总结相关推荐
- C陷阱与缺陷--读书笔记3 语义“陷阱”
第三章 一.知识点 1.C语言中的数组值得注意的地方有以下两点:(P41) (1).C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来.然而,C语言中数组的元素可以是任何类型的对象 ...
- C陷阱与缺陷阅读笔记(上)
词法陷阱 1.贪心法 C编译器对C语言符号的识别,基于每一个符号应该包含尽可能多的字符原则. 如果输入流截止至某个字符之前都已经分解成为一个个符号,那么下一个符号将包括从该字符之后可能组成一个符号的最 ...
- C陷阱与缺陷学习笔记
导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指 ...
- C陷阱与缺陷阅读笔记(下)
关于printf函数 printf函数将数据写到标准输出,fprintf函数将数据写到任何文件,sprintf函数格式化字符串.这三个函数的返回值都是已经处理的字符数. sprintf函数作为输出数据 ...
- 《C语言陷阱和缺陷》笔记
原著:Andrew Koenig - AT&T Bell Laboratories Murray Hill, New Jersey 07094 翻译:lover_P 修订:CQBOY 来自:h ...
- 《c陷阱与缺陷》笔记--注意边界值
如果要自己实现一个获取绝对值的函数,应该都没有问题,我这边也自己写了一个: void myabs(int i){if(i>=0){printf("%d\n",i);}else ...
- C陷阱与缺陷(C Traps and Pitfalls)读书笔记
说在前面:为了监督自己养成主动读书获取知识的习惯,特此写一篇博客作为读书笔记,由于是第一次主动正式写读书笔记,免不了语言错误或有不妥的地方,欢迎直接指出,不需要给博主留面子!
- 【读书笔记】《能力陷阱》——改变思想从行动开始
内容简介 <能力陷阱>原译书名为<逆向管理>英文书名为<Act like A leader Think like A leader>作者尼亚 伊贝拉,现书名是樊登老 ...
- 读书笔记软件调试之道 :问题的核心-如何修复缺陷
声明:本文档的内容主要来源于书籍<软件调试修炼之道>作者Paul Butcher,属于读书笔记.欢迎转载! ---------------------------------------- ...
- 【2018深信服 醒狮计划】《C陷阱与缺陷》学习笔记
2018深信服"醒狮计划"笔记 先自我介绍一下,湖大研一计算机的菜鸡,本科网络工程的,大学里不务正业一直在做应用,大一自学过一段时间的MFC,Windows网络编程,感觉比控制台好 ...
最新文章
- opencv-contrib配置过程
- 谈C++求a+b(大神勿喷)
- How to make a Logical Volume ON AIX5.3
- Word -- 列表重新编号
- Java面试进阶:Dubbo、Zookeeper面试题锦集
- 安装pycrypto 2.6.1各种坑
- 前端每日实战:151# 视频演示如何用纯 CSS 创作超能陆战队的大白
- java 修改Chrome浏览器的默认下载路径
- win7 右键无法新建txt
- native react 图片多选_N-第三方-react-native-image-picker,选择图片上传
- MATLAB实现变限积分函数的积分/ 多重积分/ 如何解决求积分显示AB浮点标量报错
- H5首屏图片加载优化
- AnyDesk 未连接到服务器。请检查您的互联网连接
- mysql怎样添加唯一标识_MySql设置唯一标识,主键等设置
- Flowerpot(单调队列)
- Openwrt-Chaos_Calmer搭建编译环境问题处理
- 【Proteus仿真】| 51单片机——MAX7219 驱动数码管
- acl 影响因子_计算机系部分会议级别和影响因子(DB、AI相关方向)
- 【软件测试】敏捷方法与测试左移
- symbian 模拟器 相关