《Linux C程序设计大全》(吴岳版) 笔记

INFO:

版次

2009年2月第1版

ISBN

9787302192114

笔记目录与书籍略有不同

  • 控制结构
    • 错误判断(goto)
      • 错误时,goto至错误处理语句(析构),释放未完成资源
      • 释放顺序与构建顺序相反

        E.g.: 1.文件不存在,goto err1

        2.文件打开失败,goto err2

        3.所需资源分配失败,goto err3

        4.內容读取失败,goto err4

        err4: free 3分配的资源

        err3: 关闭2打开的文件

        err2:

        err1:

        返回错误码

    • 短路计算

      可使用位运算代替乘法和除法中的2倍数,尽量避免使用除法。

    • 循环语句
      • 条件中避免使用函数,避免造成函数的重复调用

        (见三-1-2)

      • 循环条件中的变量可使用局部变量(尽量避免使用全局变量作为循环条件)

        (见二-5-5)

    • 条件判断
      • switch有一个跳转表,执行速度很快,但跳转表会占用更多空间
    • 控制结构的优化
      • 各控制结构之间可互相替换(基本符号等除外)
      • switch以空间换实间。
      • If…else…连接判断应以概率大的选项为首,依次排序。
      • 尽量使用+=、-=、++、--代替=,可节省时间和内存。(相对复杂的语句的除外)
      • 避免将循环算子使用率高的变量设置为全局/静态变量,编译器会自动优化至寄存器,全局/静态变量是在内存中。

        (同三-5-2)

  • 函数
    • 函数的本质
      • 函数名是一种指针,局部变量存储于栈中,用后即毁。

        (见四-3)

      • 访问函数时会经过:函数入栈→保存寄存器值→保存返回地址→跳转。

        (见三-5-1)

    • 声明与定义
      • 声明:仅告知编译器变量的存在,不分配存储空间。

        E.g.:int a;

      • 定义:告知编译器变量的存在,且分配存储空间。赋值不是定义

        E.g.:int a=3;//此为定义

      • 当变量的作用域内只有声明而没有定义时,编译器会自动将第一个声明默认为变量的定义。

        E.g.:int a;//此为声明,因没有定义,默认为定义

        a=3;//这里仅仅是赋值

      • 多文件的符号的声明与定义规则:
        • 不允许对同一个符号(变量或函数)有多个定义。
        • 如果该符号有一个定义和多个声明,则编译器选择被定义的符号。
        • 如果该符号有多个声明,则从其中任选一个作为符号的定义。

           

    • 全局变量
      • 全局变量(函数外定义),存储与数据段,作用于从该行开始至整个程序的结束。

        (见三-)

        E.g.:int add(int a, int c)

        { return a + b + c) }//b暂未声明,引发错误

        int b=10; //b的作用域为从声明开始至程序结束。

        int mule(int a)

        { return a * b) }//此处的b为全局变量b

        //END-----------

      • 初始值为0,自动初始化。
      • static声明的全局变量,作用域将改变为本文件。

        (见三-4-1)

    • 局部变量
      • 作用于函数/复合语句内,存储于堆栈内,用后即毁。
      • 不会自动初始化,数值随机。
      • static声明的局部变量,作用域不变,不再销毁。

        (见三-4-2)

    • static的使用
      • static声明的全局变量生命周期不变,作用域缩小至本文件。
      • static声明的局部变量作用于不变,生命周期为整个程序执行期间。
      • static声明的函数作用域为本文件,以实现封装和模块化。

        (见三-6-4)

           

    • 优化
      • 因函数是以时间交换空间,应尽量减少函数的调用。
      • 调用频率很高的局部变量会存储与寄存器内,但全局变量依旧存储于数据段,故应将高频率使用(如循环算子)设置为局部变量。

        (同二-5-5)

      • register类型:寄存器变量,被声明的变量优先分配至寄存器。
    • 多文件程序
      • auto类型:自动类型,由编译器自动决定存储位置和性质。
      • extern类型:外部变量,函数默认为extern类型,使其可以被外部文件调用。
      • 使用static改变函数和变量的生命周期。

        (见三-4)

      • C语言中一个文件就是一个模块。
      • static声明的变量和函数无法被外部文件访问,增加文件的安全性,以此实现封装和模块化,使文件隐藏细节,只对外暴露接口。修改模块时,尽量不要修改接口。
      • 链接规则
        • 符号的声明与定义

          (见三-2-4)

    • 可变参数
      • 引用:stdarg.h

        va_list parameter;//接收到的包含所有参数的参数列表

        va_start(va_list,first parameter)//定位至第一个参数

        va_arg(va_list, type)//得到下一个参数

        va_end(va_list)//参数处理结束

  • 指针
    • sizeof,屏蔽细节,使其具有更好的移植性
    • 指针
      • 指针别名

        (见四-)

      • type (*p) [size]p为数组的指针,应用整个数组;p++表示指针跳过整个数组,获取数组内容需转换为(type *)类型。
      • 函数的参数为原值的副本,修改变量需传递变量的指针,修改指针需传递指针的指针…
      • void *:指针本质为无符号整型,但C语言不允许不同类型的指针比较。可用void *代替任意类型的指针(未说明该指针指向的数据占用空间的大小),void*类型可以参与运算,但无法调用其指向的数据。
    • 函数指针
      • type (*p) (parameterlist):常被用于回调函数,type常被定义为void*类型,void*被当作泛型,损失效率
      • 函数指针数组 type (*p[size])(parameterlist)
    • const
      • 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语言高级命令
    • 结构体
      • 为了提高速度,结构体使用了内存对齐,以空间换取时间,合理改变结构体的顺序可以优化存储空间,但嵌入式等系统中为了节省存储空间一般会禁用对其机制。
    • 位运算
      • 掩码运算:获取所需字节/标志位信息。为了节约存储空间,通常将多个标识符存储于一个字节中。
    • 预处理
      • 本模块函数使用static(功能类似于private)

        (见三-3-5)

      • 头文件内容:

头文件区

其他头文件

全局宏区

共定义(如调试开关、缓冲区大小等)

全局变量区

非static函数/变量的声明

函数接口区

所有模块的函数接口

   

comon.h

结构体,声明函数接口,全局变量

list.c

函数内容,所有函数均为接口

main.c

main函数,包含common.h头文件即可

  • 调试开关

    使用条件编译,使代码调试段不再编译,不必依次注释调试语句

    #define DEBUG 1//调试开关

    #ifdef DEBUG//调试语句

    #define PRINT(str) printf(str);

    #define PRINT!(str, arg); printf(str, arg);

    #else//若调试开关关闭,则调试语句无效

    #define PRINT(str);

    #define PRINT!(str, arg);

    #endif

  • inline :将函数在编译时直接展开到代码段,执行函数不再跳转,提高执行效率。类似于宏(不是宏)。

    只有短的,少量的函数会被展开,是否展开由编译器决定。对递归无效。

  • restrict:确定指针参数的唯一性。用于优化编译。

.

   

猜你喜欢

转载自www.cnblogs.com/AlMirai/p/12519864.html