《Linux C程序设计大全》(吴岳版)
书籍信息
| 书名 | 《Linux C程序设计大全》 |
| 作者 | 吴岳 |
| 版次 | 2009年2月第1版 |
| ISBN | 9787302192114 |
- 笔记目录与书籍略有不同
- 部分编号有误
- 未包含整本书内容
二. 控制结构
错误判断(
goto)错误时,
goto至错误处理语句(析构),释放未完成资源释放顺序与构建顺序相反
e.g. 1
2
3
4
5
6
7
8
9
10文件不存在,goto err1
文件打开失败,goto err2
所需资源分配失败,goto err3
內容读取失败,goto err4
…
err4: free 3分配的资源
err3: 关闭2打开的文件
err2:
err1:
返回错误码
短路计算
- 可使用位运算代替乘法和除法中的2倍数,尽量避免使用除法
循环语句
- 条件中避免使用函数,避免造成函数的重复调用 (见三-1-1.
- 循环条件中的变量可使用局部变量(尽量避免使用全局变量作为循环条件) (见二-5-1.
条件判断
switch有一个跳转表,执行速度很快,但跳转表会占用更多空间
控制结构的优化
- 各控制结构之间可互相替换(基本符号等除外)
switch以空间换实间if…else…连接判断应以概率大的选项为首,依次排序- 尽量使用
+=、-=、++、--代替=,可节省时间和内存。(相对复杂的语句的除外) - 避免将循环算子使用率高的变量设置为全局/静态变量,编译器会自动优化至寄存器,全局/静态变量是在内存中 (同三-5-1)
三. 函数
函数的本质
- 函数名是一种指针,局部变量存储于栈中,用后即毁 (见四-1.
- 访问函数时会经过:函数入栈→保存寄存器值→保存返回地址→跳转 (见三-6-1.
声明与定义
声明:仅告知编译器变量的存在,不分配存储空间。
e.g. 1
int a;
定义:告知编译器变量的存在,且分配存储空间。赋值不是定义
e.g. 1
int a=3; //此为定义
当变量的作用域内只有声明而没有定义时,编译器会自动将第一个声明默认为变量的定义。
e.g. 1
2int a; //此为声明,因没有定义,默认为定义
a=3; //这里仅仅是赋值多文件的符号的声明与定义规则:
- 不允许对同一个符号(变量或函数)有多个定义
- 如果该符号有一个定义和多个声明,则编译器选择被定义的符号
- 如果该符号有多个声明,则从其中任选一个作为符号的定义
全局变量
全局变量(函数外定义),存储与数据段,作用于从该行开始至整个程序的结束 (见三-)
e.g. 1
2
3
4
5
6
7
8
9
10
11int add(int a, int c)
{
//b暂未声明,引发错误
return a + b + c;
}
int b=10; //b的作用域为从声明开始至程序结束。
int mule(int a)
{
//此处的b为全局变量b
return a * b
}初始值为
0,自动初始化static声明的全局变量,作用域将改变为本文件 (见三-5-1.
局部变量
- 作用于函数/复合语句内,存储于堆栈内,用后即毁
- 不会自动初始化,数值随机
static声明的局部变量,作用域不变,不再销毁 (见三-5-1.
static的使用static声明的全局变量生命周期不变,作用域缩小至本文件static声明的局部变量作用于不变,生命周期为整个程序执行期间static声明的函数作用域为本文件,以实现封装和模块化 (见三-7-1.
优化
- 因函数是以时间交换空间,应尽量减少函数的调用
- 调用频率很高的局部变量会存储与寄存器内,但全局变量依旧存储于数据段,故应将高频率使用(如循环算子)设置为局部变量 (同二-5-1.
register类型:寄存器变量,被声明的变量优先分配至寄存器
多文件程序
auto类型:自动类型,由编译器自动决定存储位置和性质extern类型:外部变量,函数默认为extern类型,使其可以被外部文件调用- 使用
static改变函数和变量的生命周期 (见三-1. - C语言中一个文件就是一个模块。
static声明的变量和函数无法被外部文件访问,增加文件的安全性,以此实现封装和模块化,使文件隐藏细节,只对外暴露接口。⚠修改模块时,尽量不要修改接口- 链接规则
- 符号的声明与定义 (见三-2-1.
可变参数
引用:
stdarg.h宏定义 说明 va_listparameter接收到的包含所有参数的参数列表 void va_start(va_list,first parameter)定位至第一个参数 type va_arg(va_list, type)得到下一个 type类型的参数void va_end(va_list)参数处理结束
四. 指针
sizeof,屏蔽细节,使其具有更好的移植性- 指针
- 指针别名 (见四-)
type (*p) [size]p为数组的指针,应用整个数组;p++表示指针跳过整个数组,获取数组内容需转换为type*类型
- 函数的参数为原值的副本,修改变量需传递变量的指针,修改指针需传递指针的指针…
void *- 指针本质为无符号整型,但C语言不允许不同类型的指针比较。可用
void*代替任意类型的指针(未说明该指针指向的数据占用空间的大小),void*类型可以参与运算,但无法调用其指向的数据
- 指针本质为无符号整型,但C语言不允许不同类型的指针比较。可用
- 函数指针
type (*p) (parameterlist)- 常被用于回调函数,type常被定义为void类型,`void`被当作泛型,损失效率
- 函数指针数组
type (*p[size])(parameterlist)
constconst修饰的变量不可改变,必须在定义的时候初始化const *const type *p=&a,可更改p的指向,不可通过指针修改内容int * const p=&a,不可更改p的指向,可通过指针修改内容const type * const p=&a,不可修改p的指向,不可通过指针修改内容。
- 修饰函数的传参和返回值,优化编译 (见)
- 优点
- 指明该变量不可更改
- 便于调试。编译器会发现
const修改无效,否则只会显示内存访问错误 - 宏替换是数据,会造成多次数据拷贝;而
const只是一个地址,只有一份数据 const定义的常量通常不分配存储空间,而是存放在符号表中,即没有读取内存的操作,提高程序效率
- 其他
- C中的
const修饰全局变量作用域已就位global,而C++中const修饰的全局变量作用域为local,需使用extern将作用域变为global。其他区别略 define在预处理阶段展开,没有类型检查,展开时并不会分配内存;const在编译运行阶段使用,编译阶段进行类型检查,一般会在内存中分配一份数据- 非
const变量传递给const变量会将变量限制为制度类型,相反却会警告或者报错
- C中的
五. C语言高级命令
结构体
- 为了提高速度,结构体使用了内存对齐,以空间换取时间,合理改变结构体的顺序可以优化存储空间,但嵌入式等系统中为了节省存储空间一般会禁用对其机制。
位运算
- 掩码运算:获取所需字节/标志位信息。为了节约存储空间,通常将多个标识符存储于一个字节中。
预处理
本模块函数使用
static(功能类似于private) (见三-3-1.头文件内容
区域 内容 头文件区 其他头文件 全局宏区 共定义(如调试开关、缓冲区大小等) 全局变量区 非static函数/变量的声明 函数接口区 所有模块的函数接口 常用文件名 说明 comon.h 结构体,声明函数接口,全局变量 list.c 函数内容,所有函数均为接口 main.c main函数,包含common.h头文件即可 调试开关
使用条件编译,使代码调试段不再编译,不必依次注释调试语句
e.g. 1
2
3
4
5
6
7
8
inline:将函数在编译时直接展开到代码段,执行函数不再跳转,提高执行效率。类似于宏(不是宏)。 只有短的,少量的函数会被展开,是否展开由编译器决定。对递归无效restrict:确定指针参数的唯一性。用于优化编译。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 AlMirai!
