《C陷阱与缺陷》笔记

2019-01-09  本文已影响0人  DayDayUpppppp
第一章 词法陷阱
  1. 整数常量
      int a = 010;      //如果整数常量的第一个字符是0开头的,那么该常量表示的是八进制
      int a = 10;
      //上面两个定义是完全不一样的,第一个是八进制表示的。
    
第二章 语法陷阱
  1. 理解函数声明

    float f;
    float f();
    float *f;
    float *f();
    float (*f)();
    
    float (*f)();   //函数声明,函数的参数是void,返回值是float
    (*f)();    //执行对应的地址的函数
    
    (float (*)())  
    //"指向返回值是float参数是void的函数指针的"的类型转换符
    
    // typedef 简化函数指针类型
    float add(float a,float b)
    {
        cout<<a<<"  "<<b<<endl;
        return a+b;
    }
    
    typedef float(*pfunType)(float, float);
    
    int main()
    {
        pfunType p = add;
        p(3.33, 2.22);
        return 0;
    }
    
  2. 注意作为结束语句的分号
    if之后不小心多写了一个分号

    if(a>b);   //一不小心多写了一个分号
    a = 100;
    

    那么,代码变成

    if(a>b) {  }
    a = 100;
    
第三章 语义陷阱
  1. 指针与数组
  1. 非数组的指针
    char * p = NULL;
    //试图打印内存地址是0的内容
    printf("printf null addr : %s \n",p);     //这个行为是未定义的,取决于不同的编译器的实现方式
    
第四章 连接
  1. 检查外部类型

    • 分析下面的代码:
      file_a.c

      int val = 100;
      

      file_b.c

      extern char val;
      cout<<val<<endl;
      

      文件的定义的类型和外部声明的类型,不一致,会出现什么情况?

      大多数编译器不能检出这样的错误,所以,这是一种很危险的行为。尤其是下面的这个情况

      char  p[] = "1234567";   //定义是数组,却声明为指针
      
      char * p;   //定义是数组,却声明为指针
      cout<<p[1]<<endl;    //妥妥的core掉
      

    原因:

  2. 头文件

    • 头文件的“比较科学”写法:
      头文件只写对应.c文件里面的变量声明
//head.h
extern int config_ip;
extern int config_pwd;
int config_ip;
int config_pwd;

static int val;   //不对外部可见
第六章 预处理

基本用法:

#宏常量
#define num 100

#宏函数
#define max(a,b)  return a>b?a:b
#define swap(a,b) \
  int tmp = a;\
  a = b;\
  b = tmp;

但是,宏的本质是文本替换,但是在很多场景下面会出现问题。用inline和const更加安全一点。

#define max(a,b) a>b?a:b

max(a,b)+1;
//替换之后,a>b?a:b+1       //和原来的有一些歧义,在某些case上面是错误的。
  1. typedef (类型定义)与宏的区别

    • 区别1: 比宏更加安全的定义
    typedef char* PCHAR;
    PCHAR pa,pb;  // = char * pa;char * pb;
    
    如果写成宏的话,可能是这样
    #define PCHAR char
    PCHAR pa,pb;   // = char * pa,pb; //= char * pa; char pb;
    
    • 区别2:用在旧的C代码中,帮助struct。
    // 用在旧的C代码中,帮助struct。以前的代码中,声明 
    // struct新对象时,必须要带上struct,
    // 即形式为: struct   结构名对象名,如:
    struct tagPOINT1
    {
      int x;
      int y; 
    } ;
    struct tagPOINT1 p1;
    
    //而在C++中,则可以直接写:结构名对象名,即:        
    tagPOINT1 p1;
    typedef struct tagPOINT
    {
      int x;
      int y;
    }POINT;
    POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,
    
    • 区别3:
      在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。
    原声明:int *(*a[5])(int, char*);
    变量名为a,直接用一个新别名pFun替换a就可以了:
    typedef int *(*pFun)(int, char*); 
    原声明的最简化版:
    pFun a[5]; 
    
    • 关于typedef


      image.png
上一篇下一篇

猜你喜欢

热点阅读