我的《C陷阱与缺陷》读书笔记
第一章 词法“陷阱”
1、 =不同于==
if(x = y)
break;
实际上是将y赋给x,再检查x是否为0。
如果真的是这样预期,那么应该改为:
if((x = y) != 0)
break;
2、 &和| 不同于 && 和 ||
3、词法分析中的“贪心法”
编译器将程序分解成符号的方法是:从左到有一个一个字符的读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符床是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号。例如:
y = x/*p; 会被解析为:/* 注释符号
4、整型常量
010(八进制数) 不同于 10(十进制)。
5、字符与字符串
首先是单引号与双引号的区别:
用单引号括起来的一个字符表示一个整数(ASCII码),而双引号括起来表示一个指针。
第二章 语法“陷阱”
1、理解函数声明
弄懂(*(void(*)())0)(); //首地址为0的函数。
float (*h)(): h是一个指向返回值为浮点型的函数的指针
所以,(float (*)()) 表示一个“指向返回值为浮点型的函数的指针”的类型转换符。
fp(): 是(*fp)( )的简写。
*fp():是 *( (*fp) ( ) )的简写。
( *0 )( );
虽然上式编译器不认,但可以把0转换为指向“返回值为void的”函数的指针,所以0可变为: ( void(*) ( ) ) 0 ,代入(*0)(),得到:
(*( void(*) ( ) ) 0) ( ) 。
该式子用等价于:
typedef void ( *func ) ( );
( *( func ) 0 ) ( );
类似的,signal.h中对signal函数的声明:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
2、运算符优先级的问题
需要补充表格
3、其他
主要是别多写分号,switch别忘了break,别写空else分支。
第三章 语义“陷阱”
1、指针与数组
Struct {
Int p[4];
Double x;
}b[17];
Int calendar[12][31];
Int (*p)[31];
Sizeof(calendar):12*31=372
calendar[0]指向该一维数组 对应*p
calendar[0][0]
......
calendar[0][30]
calendar[1]指向该一维数组 对应*(p+1)
calendar[1][0]
......
calendar[1][30]
…….
......
……
calendar[11]指向该一维数组对应*(p+11)
calendar[11][0]
......
calendar[11][30]
2、内存分配
free(r);
用malloc显式分配的空间,不会再退出本函数后自动释放掉,而是会等程序员显式释放后才消失。
注意检查,malloc分配的内存可能失败。
C语言中会自动地将作为函数参数的数组声明转换为对应的指针声明,如:
int strlen(char s[ ]){ }等价于int strlen(char *s){ }
但在其他情形下不会自动转换,也就是说不等价,如:
extern char hello[ ];和extern char *hello;完全不同。
边界计算
自己实现一个memcpy函数:
void memcpy(char *dest, const char *source, int k)
{
while( --k >= 0 )
*dest++ = *source++;
}
说到底就是,操作时一定要知道操作数据的长度。
整数溢出
两个有符号整数相加会发生溢出。
两个无符号整数相加不会发生溢出。
一个有符号和一个无符号整数相加,因为有符号被自动转换成无符号,所以也不会溢出。
第四章 连接
编译器一般每次只处理一个文件。编译器的责任是把C源程序翻译成对连接器有意义的形式。
许多系统中的连接器是独立于C语言实现的,因此如果链接时候错误原因是与C语言相关的,连接器无法判断错误原因。但连接器能够理解机器语言和内存布局。
典型的连接器把由汇编器或编译器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体。
连接器通常把目标模块看成是由一组外部对象组成的。每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来识别。因此,程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个外部对象。static的不会与其它源程序文件中的同名函数或同名变量发生冲突。对于非satatic的函数或变量的名称冲突的解决办法将在后面讨论。
除了外部对象外,目标模块中还可能包括了对其他模块中的外部对象的引用,当连接器读入一个目标模块时,它必须解析出这些引用,并作出标记说明这些外部对象不再是未定义的。
连接器的输入是一组目标模块文件和库文件。输出是一个载入模块。
避免外部变量的函数的冲突和不一致等问题的办法:
每个外部对象只在一个头文件里声明,需要用到该外部对象的所有模块都应该包括这个头文件。定义该外部对象的模块也应该包括这个头文件。
第五章 库函数
没什么好说的,就是apue的一些函数而已。
第六章 预处理器
宏定义:主要是理解宏不是函数,而是直接替换
1、 不能忽视宏定义中的空格:
#define f (x) ( (x)-1 ):因为f后面多了一个空格,所以f(x)代表(x) ( (x)-1 )
2、 宏并不是函数,所以注意那些括号:
如:#define abs(x) ( ( (x) >= 0)?(x):-(x) )
#define max(a,b) ( (a)>(b)?(a):(b) )
3、 宏并不是语句
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
4、 宏不是类型定义
错误用法: #define int_8_ int*
int_8 a,b; //则a是指针,b是int型
正确用法应该用typedef
typedef int * int_8_;
第七章 可移植性缺陷
主要是:
1、 应对C语言标准的变更;
2、 标识符名称的限制;
3、 整数的大小;
4、 字符是有符号整数还是无符号整数;
5、 移位运算符;
1)在向右移位时,空出的位是由0填充还是1,还是由符号位的副本填充?
如果被移位对象是无符号数,那么由0填充;如果是有符号数,那么是0或符号位的副本。
2)移位操作的位数允许的取值范围是什么?
如果被移位对象的长度是n位,那么移位计数必须大于或等于0,而严格小于n。
6、 移植性需考虑的地方:
1)机器的字符表不同。
2)有的机器是one's complement,有的机器是two's complement的。基于2的补码的计算机,所允许表示的附属取值范围要大于正数取值范围,所以有时取负值的运算会导致溢出。
3)各机器对取模运算的定义不同。
第八章 惯用与答案
将惯用的c == '\t' 写作 '\t' == c。一旦写错成=号,编译器就能检查出来。
我的《C陷阱与缺陷》读书笔记的更多相关文章
- C陷阱与缺陷读书笔记
2.1理解函数声明 这一章仔细分析了(*(void(*)())0)();这条语句的含义,并且提到了typedef的一种函数指针类型定义的用法. 我们经常用到的typedef用法是用于指定结构体的类型, ...
- C陷阱和缺陷学习笔记
这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 ...
- C的陷阱和缺陷研读笔记01
词法分析: 编译器将程序分解成符号的方法是 从左到右一个一个字符的读入,如果该字符可能组成一个符号,再读入下一个字符 而c语言里的符号 / * =只有一个字符长, 是单字符的, /* == 一些事双字 ...
- 软件测试价值提升之路- 第三章"拦截缺陷 "读书笔记
作为一个测试团队,基本的职责是:测试产品,发现缺陷,报告结果,使每个版本的测试水准稳步提升.这些价值是作为一个测试所必须具备的,发挥这些价值能够让测试获得研发团队的基本信任.这类价值分为3部分: 1) ...
- C陷阱与缺陷学习笔记
导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指 ...
- C的陷阱和缺陷研读笔记02
宏: 宏不是函数 展开会产生庞大的表达式 #define MIN(A,B) ((A) <= (B) ? (A) : (B))MIN(*p++, b)会产生宏的副作用 剖析: 这个面试题主要考查面 ...
- 《c陷阱与缺陷》笔记--注意边界值
如果要自己实现一个获取绝对值的函数,应该都没有问题,我这边也自己写了一个: void myabs(int i){ if(i>=0){ printf("%d\n",i); }e ...
- 《c陷阱与缺陷》笔记--移位运算
#include <stdio.h> int main(void){ int a = 2; a >> 32; a >> -1; a << 32; a & ...
- 读书笔记--C陷阱与缺陷(七)
第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一 ...
- 读书笔记--C陷阱与缺陷(一)
要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便). 看到大家都推荐看看 C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅. 决定将 ...
随机推荐
- Python下科学计算包numpy和SciPy的安装【原创】
Python下大多数工具包的安装都很简单,只需要执行 "python setup.py install"命令即可.然而,由于SciPy和numpy这两个科学计算包的依赖关系较多,安 ...
- 进度对话框 ProgressDialog 用法总结
ProgressDialog 继承自AlertDialog,AlertDialog继承自Dialog ); dialog.setButton(DialogInterface.BUTTO ...
- 开发者和系统管理者最喜爱的开源工具Vim 起步学习的五个技巧
多年来,我一直想学 Vim.如今 Vim 是我最喜欢的 Linux 文本编辑器,也是开发者和系统管理者最喜爱的开源工具.我说的学习,指的是真正意义上的学习.想要精通确实很难,所以我只想要达到熟练的水平 ...
- Virtualbox中Linux添加新磁盘并创建分区
原文:https://www.linuxidc.com/Linux/2017-01/139616.htm ----------------------------------------------- ...
- 不同版本(2.3,2.4,2.5,3.0)的Servlet web.xml 头信息
不同版本(2.3,2.4,2.5,3.0)的Servlet web.xml 头信息 学习了:https://blog.csdn.net/z69183787/article/details/360080 ...
- 美团的android多渠道包的3种方法
转: http://tech.meituan.com/mt-apk-packaging.html 美团Android自动化之旅—生成渠道包 zhihu2014-06-13 10:06 概述 每当发新版 ...
- Python 中的几种复制文件的用法
1. os.system Python code import os import tempfile filename1 = tempfile.mktemp (".txt") #产 ...
- java接口的高级应用
直接上菜 /*接口类*/ public interface MsgListener{ public void afterMsgRecived(String msgData); } /*工具类*/ pu ...
- Android开发笔记(一百三十四)协调布局CoordinatorLayout
协调布局CoordinatorLayout Android自5.0之后对UI做了较大的提升.一个重大的改进是推出了MaterialDesign库,而该库的基础即为协调布局CoordinatorLayo ...
- jquery api 常见api 元素操作例子
append_prepend.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ...