zoukankan      html  css  js  c++  java
  • 《C陷阱和缺陷》读书记录

    2015年5月10日    星期日 12:11

    第1章 词法“陷阱”

    • =不同于==
    • &和|(按位运算符)不同于&&和||(逻辑运算符)
    • 词法分析中的“贪心法”
    • 整型常量,整型常量第一个字符为0被视为八进制,10和010含义截然不同
    • 字符和字符串
      • 用单引号引起的一个字符代表一个整数,如'a'含义与0141(八进制)或97(十进制)一致
      • 用双引号引起的字符串,代表一个指向无名数组起始字符的指针

    第2章 语法“陷阱“

    • 理解函数声明

        声明=类型+声明符,(*(void(*)())0)()的含义是?--->(void(*)())0将0强制转化为”指向返回值为void类型的函数的指针“

    • 运算符优先级问题

        if(flags & FLAG!=0)等价于 if(flags &(FLAG!=0))

        r=hi<<4+low等价于 r=hi<<(4+low)   ,优先级影响运算的顺序,有时候并不是程序员设想的那样计算

      • 优先级最高的并不是真正意义上的运算符,函数调用(),数组下标[],结构成员选择->,点操作符.,都是自左向右结合
      • 单目运算符优先级次于上述运算符,*p()编译器会解释为*(p()),与(*p)()不一样。自右向左结合,所以*p++和(*p)++是不一样的  
      • 双目运算符优先级最低,算数>移位>关系>逻辑>赋值>条件运算符
      • 逗号操作符优先级最低
    • 注意作为语句结束标志的分号,if或者while字句后面多写/少写分号
    • switch语句,break 语句,fall through现象
    • 函数调用,f();这是函数调用,f;这表示计算f的地址,并不调用它
    • ”悬挂”else引发的问题

    第3章 语义“陷阱"

    • 指针和数组
      • C语言中只有一维数组,但是数组元素可以是数组,”仿真“出多维数组
      • 除了数组长度和指向数组下标为0的元素指针,其他操作都是通过指针完成
    • 非数组的指针

       动态分配内存存储字符串,需要注意的三个问题

      • 检查是否分配成功
      • malloc显示分配内存,必须显示释放内存
      • 字符串存储内存需要多一个空间存放结束标志('')
    • 作为参数的数组声明,数组名作为函数参数会立刻被换为指向该数组第一个元素的指针,C语言中自动将作为参数的数组声明转换为相应的指针声明
    • 避免”举隅法“,以部分代替整体,以整体代替部分。char *p;p="xyz"; p仅指向x元素
    • 空指针并非空字符串,NULL,任何试图使用NULL指针所指向的内存中的内容都是不合法的
    • 边界计算与不对称边界
    • 求值顺序,&&,||首先对左侧求值,只有在需要时才对右侧求值
    • 运算符&&,||和! 与&,|,~的区别
    • 整数溢出,有符号数与无符号数运算,结果为无符号数,不发生溢出。两个有符号数运算,”溢出”可能发生。解决方法(转为无符号数运算,判断a>INT_MAX-b是否成立)
    • 为函数main提供返回值,如果为显示声明返回类型,默认为int

        

    第4章 连接

    • 什么是连接器

        输入:一组目标模块和库文件

        输出:载入模块(可执行文件实体)

    • 声明和定义 int a;定义,int a=7;定义并初始化,extern int a;声明表示了这是对外部变量a的引用
    • 命名冲突与static修饰符,static int a;将a的作用域限制在一个源文件中,对于其它源文件,a是不可见的
    • 形参、实参和返回值,在函数声明中可以省略参数类型说明,但是float类型参数会自动转化成double,char和short会转换为int
    • 检查外部类型

        一个文件包含 char filename[]="etcpasswd";

        另一个文件包含声明 extern char *filename;

        这种方式并不提倡,毕竟字符串数组和字符指针类型不同,而且它们使用的存储方式也不一样

    • 头文件,每个外部对象只在一个地方声明,一般就在头文件中 

    第5章 库函数

    • 返回整数的getchar函数,返回标准输入文件的i下一个字符,类型为int
    • 更新顺序文件,允许程序打开一个文件的同时进行读出和写入操作,但一个输入操作不能随后直接跟一个输出操作,反之亦然,如果要同时进行输入和输出操作,插入fseek函数
    • 缓冲输出与内存分配,setbuf(stdout,buf),所有写到stdout的输出都应该使用buf作为缓冲,直到buf满或者程序员调用fflush,buf缓冲区中的内容才实际写到stdout中
    • 使用errno检测错误
    • 库函数signal

    第6章 预处理器

      在严格意义上的编程过程开始之前,C语言预处理器首先对代码进行必要的转换处理。

    • 不能忽略宏定义中的空格 #define f   (x)  ((x)-x)和 #define f(x)  ((x)-1)两种含义
    • 宏并不是函数
      • 宏定义中的括号,预防引起与优先级有关的问题
      • 宏定义中的表达式中的操作数可能被求值多次,多以自增自减操作符需要慎重使用
      • 混合了宏和递增运算(评,简直是chaos)
    • 宏并不是语句
    • 宏并不是类型定义 
      #define T1 struct foo *
      typedef struct foo *T2;
      T1 a,b; /*a是指针,但b是结构*/
      T2 a,b; /*a,b均为指向结构的指针*/  

    第7章  可移植性缺陷

    • 应对C语言标准变更,函数原型的概念,新旧标准定义方式不同
    • 标示符名称的限制,编译器识别标识符最大长度,不区分外部名称大小
    • 整数的大小,short,int,long字符长度由硬件特性决定
    • 字符是有符号整数还是无符号整数
      • 将一个字符值转换为一个较大的整数时,需要考虑它的有无符号问题
      • 如果C是字符变量,(unsigned)c并不一定会得到c等价的无符号整数。因为将字符c转为无符号数时,首先转换为int,正确语句应为(unsigned char)c
    • 移位运算符,向右移位时,逻辑右移还是算数右移。移位计数允许的取值范围是什么(大于等于0,严格小于位数n)
    • 内存位置0
    • 除法运算时发生的截断
    • 随机数的大小
    • 大小写转换,如果输入的大小写字母都是无效呢
    • 首先释放,然后重新分配。 
  • 相关阅读:
    使用Nginx搭建http服务器
    (七)Docker搭建httpd集群
    zlib库对文件进行压缩和解压操作
    (一)Apache Thrift 的使用
    (一)select、poll、epoll
    (十三)备忘录模式
    (十二)命令模式
    (十一)迭代器模式
    centos下利用httpd搭建http服务器方法
    shell快捷键
  • 原文地址:https://www.cnblogs.com/sherPur/p/4547867.html
Copyright © 2011-2022 走看看