再温C语言小记

2019-04-24  本文已影响0人  那个人一定不是我
char* stackValue(void){
    char str[20] = {'A'};
    return str;
}

void stackChange(void){
    char str[20] = {'B'};
}


int main(int argc, char * argv[]) {
    
    int  result_i = 0;
    unsigned long result_ul = 0;
    
    int num_i = 0;
    
    /*- ','逗号运算符 -*/
    //赋值运算符的优先级别高于逗号运算符,逗号运算符是所有运算符中级别最低的
    result_ul = 2, 3;   //值为2
    result_ul = (2, 3); //值为3
    
    /*- 符号的贪婪操作,从左往右匹配到最多的符号,后置运算与编译器相关 -*/
    num_i = 3;
    result_ul = num_i+++num_i;
    //num_i值为3; result_ul值为7 编译器相关
    num_i = 3;
    result_ul = (++num_i) * (++num_i) * (++num_i);
    //num_i值为6; result_ul值为120 = 4*5*6
    num_i = 3;
    result_ul = (num_i++) * (num_i++) * (num_i++);
    //num_i值为6; result_ul值为60 = 3*4*5 编译器相关
    
    /*- 返回栈地址 危险操作-*/
    char* stackRet = stackValue();
    char old_c = stackRet[0]; //'A'
    stackChange();
    char change_c = stackRet[0]; //'B'
    //数据由‘A’变为‘B’,地址对应的栈空间数据被修改
    
    /* '*' 和 '[]'的优先级, 数组指针, 指针数组 */
    int * ary[10] = {}; //'[]'的优先级高,这里是数组,存在的是‘int *’
    int (*ary_p) [10] = NULL; //指针,指向储存’Int‘的数组
    
    /* 指针加一 数组变量加一 首元素加一 */
    char num_ary[5]={'A','B','C','D','E'};
    
    //&num_ary值为数组的地址,类型为'char (*) [5]',
    //加一地址为数组结束后的地址
    char* c_p = (char*)(&num_ary + 1);
    char c_1 = *(c_p - 1); //值为'E'
    //指针类型强转为'char *',减一变为数组最后一个元素的地址
    
    //num_ary与&num_ary[0]值相等为第一个元素地址且类型一致为’char*‘
    char c_2 = *(num_ary + 1); //值为'B'
    char c_3 = *(&num_ary[0] + 1); //值为'B'
    
    /* 数组初始化指定位置 */
    int new_ary[] = {
        ['A'] = 9,
    };
    //将创建储存66个Int的数组,由于‘A’的char值为65,new_ary[65] = 9;

    /* sizeof 为关键字不是函数 */
    int test[10];
    result_ul = sizeof(test);      //sizeof(int) * 100
    result_ul = sizeof(test[11]);
    result_ul = sizeof(&test);
    result_ul = sizeof(&test[11]);
    //sizeof在编译阶段进行处理获取值,运行阶段是不会执行‘test[11]’越界访问
    
    /* const 修饰,去掉类型观看*/
    int const * con_p1 = &num_i;  //修饰指针对应的内容
    int * const con_p2 = &num_i;  //修饰指针
    const int * con_p3 = &num_i;  //去掉类型‘int’观看,同con_p1;
    //*con_p1 = 7;     //编译失败
    //con_p2 = &result_i; //编译失败
    
    /* 预处理的 #define #undef */
#define X  1
#define Y   X*2
#undef  X
    //result_i = Y; //编译失败:‘X’未定义
    
    /* volatile 关键字: 易失的;易变的*/
    //http://www.cnblogs.com/god-of-death/p/7852394.html
    /* register 关键字 */
    register int num_reg = 1;
    //int* num_reg_p = &num_reg; //编译错误,寄存器无法获取地址

    
    /* enum 内存大小 */
   /*enum变量占用的空间与编译器相关。
    C标准:“枚举型尺寸是能够容纳最大枚举子值的整数尺寸”,
    “枚举类型中枚举子的值必须要能用一个int型表述”。
    也就是说,枚举型的尺寸不能超过int型,但不必等于int型,
    只要能容纳最大枚举子就行。
    gcc也有类似选项-fshort-enums,设置后就选用节省内存的enum长度。*/
    enum Color{
        Color_a = CHAR_MAX,
        Color_b = CHAR_MIN,
    } Color;
    
    result_ul = sizeof(Color);
    result_ul = sizeof(Color_a);
    
    /* union 内存大小 */
    /*1.联合就是一个结构;
      2.它的所有成员相对于基地址的偏移量都为0;
      3.此结构空间要大到足够容纳最“宽”的成员;
      4.其对齐方式要适合于联合中所有类型的成员。 */
    union U1{
        char s[9];
        char n;
    };
    
    union U2{
        char s[9];
        int n;
    };
    
    union U3{
        char s[9];
        double n;
    };

    result_ul = sizeof(union U1);  //9
    result_ul = sizeof(union U2);  //12
    result_ul = sizeof(union U3);  //16
    
    
    /* struct 内存大小 */
    /*1.结构体的对齐最大单位:使用了‘pack’宏则用指定的值,
        没有指定则使用结构体成员类型的最大值
       (成员为数组取存储元素的类型大小用于判断,
        成员为结构体取它的对齐最大单元用于判断),
    
      2.成员的偏移量:如果其类型大小小于对齐最大单位,
        那么前面占用空间必须为其类型大小的整数倍;
        如果其类型大于对齐最大单位,
        那么前面占用空间必须为对齐最大单位的整数倍。
        (所以‘pack’宏的值只能是基础类型对应值:‘0,1,2,4,8,16’)*/
    struct empty_struct {
    }empty_struct;
    result_ul = sizeof(empty_struct); //0
    
#pragma pack(2)
    typedef struct{
        char c1[3];  //0
        char*  c2;  //4
    }T_U1;
#pragma pack(0)

    
#pragma pack(4)// -> pack(1)
    typedef struct{   //默认对齐大小最大值为4(i成员类型值最大4,uu为2)
        char  c1;  //0 -> 0
        short s;   //2 -> 1
        char  c2;  //4 -> 3
        int   i;   //8 -> 4
        char cc[20]; //12 -> 8
        T_U1 uu;  //32 -> 28
    }T_Struct;
#pragma pack()

    
    T_Struct one;
    
    result_ul = sizeof(one); //44 -> 40
    
    unsigned int start_addr = (unsigned int)(void*)&one;
    result_ul = (unsigned int)(void*)&one.c1 - start_addr;
    result_ul = (unsigned int)(void*)&one.s  - start_addr;
    result_ul = (unsigned int)(void*)&one.c2  - start_addr;
    result_ul = (unsigned int)(void*)&one.i  - start_addr;
    result_ul = (unsigned int)(void*)&one.uu  - start_addr;

}


Demo覆盖的内容:

  1. 返回栈地址
  2. ‘,’号运算符
  3. struct大小 设置对齐大小 空结构图
  4. enum大小 空 有值
  5. 符号的贪婪操作
  6. ‘*’‘[]’的优先级 数组指针 指正数组
  7. 指针加一 数组变量加一 首元素加一
  8. 预处理的 define undefine
  9. volatile 关键字
  10. 数组初始化指定位置
  11. sizeof 关键字不是函数
  12. const 修饰
  13. union 大小

看下面的Refs比上面的好看多了^_^
Refs:
《C语言深度剖析》

上一篇下一篇

猜你喜欢

热点阅读