《C专家编程》——笔记整理

第一章:C的时空

1、可移植的代码——严格遵循标准(ANSI C)的程序
(1)只使用已确定的特性;
(2)不突破任何由编译器实现的限制;
(3)不产生任何依赖编译器定义的或未定义的特性的输出。

2、无符号类型
(1)尽量不要在代码中使用无符号类型,以避免增加不必要的复杂性;
(2)尽量使用有符号类型,在涉及混合类型升级时,不必担心边界情况;
(3)只有使用位段和二进制掩码是,才可用无符号类型,并使用强制类型转换来确保操作数类型相同;
(4)有符号类型和无符号类型运算时,会转化成无符号类型,再进行运算;

第二章:语言特性

1、差一错误——strlen
直觉性错误:malloc(strlen(str)) -->> malloc(strlen(str) + 1)

2、NUL和NULL
NUL:ASCII码值为0000 0000,常用于结束一个ASCII码字符串,即字符串末尾的'\0',
NULL:空指针

3、switch
(1)fall through:case后面不加break语句时,switch会依次执行下去,除非某些特殊情况,几乎所有的case都需要以break结尾。
(2)break语句跳出最近的循环语句或者switch语句。

4、函数的全局可见性
函数定义时,缺省修饰符的情况下,默认函数作用域为全局可见。指定文件范围时,需要添加static说明。

5、符号重载
(1)static:在函数内部,修饰变量时表示变量的值在调用期间保持连续性;在函数这一级,表示函数只对本文件可见;
(2)extern:用于函数定义,表示全局可见(冗余);用于变量,表示在其他地方定义;
(3)sizeof:操作符,操作数为类型名时,两边必须加上括号;操作数如果是变量则不必加括号;

6、运算符的优先级
(1)运算符*的优先级较低:[]高于*,如int *a[]中a表示的是元素为int指针的数组,即int* (a[]);函数()高于*,如int *fp()中fp表示返回值为int*的函数,即int *(fp());
(2)算术运算符高于位移运算符,即mas << 4 + lsb表示msb << (4 + lsb);
(3)建议:牢记乘法和除法优先于加法和减法,在涉及其他的操作符时一律加上括号

第三章:声明

1、组合类型

(1)结构体 struct

struct 可选的结构标签 {  
	类型1 标识符1;  
    类型2 标识符2;  
    类型3 标识符3;

	类型N 标识符N;	

} 可选的变量定义;

考虑到可阅读性以及语句功能的单一性,建议变量的声明与类型的声明分开,如:

// 类型声明  
struct fruit_tag {
	int color;
	int weight;
	int number;
};

// 变量定义
struct s_tag orange;

(2)联合体 union
在联合体中,所有成员都是从便宜地址零开始存储;各个成员的位置存在重叠,某一时刻只有一个成员真正存储在该地址。 常用来节省空间。

联合体的外部结构基本与结构体相同,仅替换关键字union:

union 可选的结构标签 {  
	类型1 标识符1;  
    类型2 标识符2;  
    类型3 标识符3;

	类型N 标识符N;	

} 可选的变量定义;

(3)枚举 enmu
将一串名字与一串整型值联系在一起,通常也可以使用宏定义实现。一般形式如下:

enmu 可选的标签 {
	标识符1;
    标识符2 = 主动赋值;
    标识符3;

	标识符N;
} 可选的变量定义;

缺省的情况下,标识符的整型值从0开始,下一次标识符的值自动加1,依次下推;如果对某个标识符进行赋值,那么后续的标识符依次加一。

枚举变量在函数运行时一直存在,而宏定义在预编译时被替换,因此,枚举变量更易于调试代码。

2、优先级规则

A 声明从最左边的标识符中读取,然后按照优先级依次读取;  
B 优先级从高到低依次是:
  B.1 声明中被括号括起来的部分;  
  B.2 后缀操作符:括号()表示函数,方括号[]表示数组;  
  B.3 前缀操作符:星号*表示“指向...的指针”;  
C 如果const或者volatile关键字后面紧跟类型说明符,则其作用于类型说明符;否则,作用域左边紧邻的指针星号。

示例: char * const *(*next)()
分析流程:
A:名称为next;
B.1:(next),表示next为一个指针;
B.2: (
next)(),表示next为一个指向函数的指针;
B.3: (next)(), 表示next为一个指向函数的指针, 该函数返回的是一个指针;
C: char * const (next)(), 表示函数返回的指针,指向一个只读的指向char的指针;

3、typedef与define的区别
typedef可以看做一种彻底的类型封装,在运行过程中有效;宏定义,仅做替换,在预编译时进行处理。

尽量避免对结构使用typedef。

可用作数组、指针和函数的组合类型,以及可移植类型。

第四章:数组和指针的差异

待续

posted @ 2022-02-20 23:49  Pangolin2  阅读(91)  评论(0编辑  收藏  举报