美文网首页
C语言基础之关键词

C语言基础之关键词

作者: Eugene_iOS | 来源:发表于2023-03-27 14:14 被阅读0次

    1、const

    const修饰全局变量

    此时全局变量只能读取,不能修改;无论是直接修改,还是指针修改。

    const修饰普通局部变量

    此时局部变量,不能直接修改;但可以通过指针修改。

    // const int a;a值不可以直接更改,但可以通过指针地址修改。
    // 这里a地址里面的值已经变更为了2,但在不同编辑器里打印的结果,可能不同。如在xcode中打印的仍是1,这涉及到编译器优化问题。
    const int a = 1;  
    int *p = &a; 
    *p = 2; 
    

    参考:
    const变量通过指针修改
    通过const指针修改变量名

    const修饰指针变量

    1、若const修饰指针变量的类型,无法通过指针变量修改地址里面的值;

    // const int *p;不能修改直接修改 *p 的值,但可以通过 p 修改。
    int a = 1;
    const int *p = &a;
    int b = 2; 
    p = &b;// 或a = 2;此时*p的值已经变更。
    

    2、若const修饰指针变量,无法修改指针变量保存的地址;

    // int *const p;不能直接修改 指针p 的值,但可以通过*p 修改。
    int a = 1;
    int * const p = &a;
    *p = 2;此时*p的值已经变更。
    

    3、若const修饰指针变量,同时也修饰指针变量的类型,则只能初始值确定变量值,其余情况下不得修改。eg:const int * const p;
    const修饰指针的三种效果


    2、struct

    结构体是一种数据构造类型
    格式1

    struct 结构体类型名 { 成员列表 };

    格式2

    // 该方式定义的变量为全局变量
    struct 结构体类型名 { 成员列表 } 结构体变量名1,变量名2;

    格式3

    // 无名结构体由于没有结构体类型名,所以定义后是无法再定义结构体变量的,只能在定义类型的同时定义结构体变量
    struct { 成员列表 } 变量名1,变量名2;

    定义结构体变量

    // 这种定义的变量内存分配位置,要看定义的位置
    struct 结构体类型名 变量3,变量4;

    定义结构体别名

    // 使用:NAME_A 变量1,变量2;不需要关键字struct
    typedef struct { 成员列表 } 重新定义的结构体类型名NAME_A;

    注意:typedef主要用于给一个类型取别名,此时相当于给当前结构体重新取类型名为NAME_A,相当于struct结构体名。

    结构体数组格式

    struct 结构体类型名 数组名[ 元素个数 ];

    结构体指针格式

    // 指针变量占4个字节,用来保存结构体的地址编号
    struct 结构体类型名 * 结构体指针变量名;

    结构体指针的引用方式

    1、(*结构体指针变量).成员
    2、结构体指针变量名->成员

    结构体内存分配问题

    规则1:以结构体中占最大的成员类型字节长度为单位开辟内存
    规则2:字节对齐。即存放类型变量的起始位置,必须是 规则1: 最大成员类型字节数 的倍数。开辟内存的时候,从上往下依次按成员在结构体中的位置顺序开辟空间。
    为什么要有字节对齐?用空间换时间,提高cpu读取数据的效率。

    位域

    struct 位域结构名 {
    位域类型 [位域名] : 位域宽度 ;
    // 位域类型:决定了如何解释位域的值。
    // 位域宽度:位域中位的数量。宽度必须小于或等于指定类型的位宽度。
    };
    示例:

    struct packed_data {
    unsigned int a:2;
    unsigned int b:4;
    unsigned int c:6;
    unsigned int d;// 不设置位域,位域默认为数据类型的字节长度
    }data;
    

    注意:
    1、不能对位域成员取地址。
    2、赋值时,不要超出位域定义的范围。
    3、位域成员的类型必须指定为整型或字符型。
    4、一个位段必须存放在一个存储单元中,不能跨两个单元;第一个单元空间不能容纳下一个位段,则该空间不用,而从下一个单元起放该位段。
    5、若位域成员列表所占位数在数据类型的字节长度内,通过sizeof()函数打印出的是位域成员数据类型的字节长度。


    3、union

    共用体:由几种不同类型的变量共同占用一段内存的结构。也称为“联合体”

    描述
    1、是和结构体类似的一种构造类型的数据结构,在进行某些算法的时候,需要使用几种不同类型的变量存到同一内存单元中,这些变量所使用的内存空间相互重叠。
    2、共用体所有成员占有同一段内存空间。
    3、共用体的大小使是其占内存长度最大的成员的大小。

    特点
    1、同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用。
    2、共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖。
    3、共用体变量的地址和他的各成员变量的地址都是同一地址。
    4、共用体的格式:union 共用体类型名称 { 成员列表 };


    4、enum

    枚举类型也是一种构造类型。
    格式enum 枚举类型名 { 枚举值列表;};
    注意:在定义枚举类型的时候枚举元素可以用等号给它赋值,用来代表元素从几开始;在程序中不能再次对枚举元素赋值,因为枚举元素是常量。


    5、strlen

    strlen库函数:size_t strlen(const char *s),这个函数接收一个字符串的指针,返回这个字符串的长度(以字节为单位);strlen返回的字符串长度是不包含字符串结尾的'\0'的。


    6、sizeof

    sizeof运算符:用来返回一个类型或者是变量所占用的内存字节数


    7、typeof

    typeof宏:使用typeof()可由结构体成员得到该成员的数据类型


    8、offsetof

    offsetof宏:用来获取结构体中某个元素相对于结构体首地址偏移量

    /** 
     * @type: 成员所嵌入的容器结构体类型
     * @member: 结构体中的成员名
     * 计算的结构体中某成员的偏移量
     * 1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
     * 2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
     * 3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址,即相对于0的偏移量,要的就这个;
     * 4. (size_t)(&(((TYPE*)0)->MEMBER))结果转换类型,size_t应该最终为unsigned int类型。
       此宏的巧妙之处在于将 0 转换成(TYPE*),这样结构体中成员的地址即为在此结构体中的偏移量。
     */ 
    #define offsetof(type, member) (size_t)&(((type*)0)->member)
    

    9、container_of

    container_of宏:根据结构体变量中某个成员的指针,反推出结构体变量的指针,继而得到结构体变量中其他的成员。实现上实际就是根据当前这个成员的地址 减去 这个成员相对整个结构体的的偏移量,就是结构体的地址,然后强制转换指定数据类型即可。

    /**
     * container_of - 通过结构体的一个成员获取容器结构体的指针
     * @ptr: 指向成员的指针
     * @type: 成员所嵌入的容器结构体类型
     * @member: 结构体中的成员名
     * 根据结构体(type)某成员变量(member)的指针(ptr),来求出该结构体(type)的首指针。
     * 1. typeof( ( (type *)0)->member )为取出member成员的变量类型。
     * 2. 定义__mptr指针ptr为指向该成员变量的指针
     * 3. mptr为member数据类型的常量指针,其指向ptr所指向的变量处
     * 4. (char *)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member))用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr -offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。
     * 5. ({ })这个扩展返回程序块中最后一个表达式的值。
     */
    #define container_of(ptr, type, member) ({ \
         const typeof( ((type *)0)->member ) *__mptr = (ptr); \
         (type *)( (char *)__mptr - offsetof(type,member) );})    
    

    写在最后

    iOS中位域(位段)的简单使用
    理解大小端字节序 - 范兵 - 博客园
    字节序(大端和小端) - flxx - 博客园
    字节序探析:大端与小端的比较 - 阮一峰的网络日志
    iOS中位域(位段)的简单使用
    Linux内核 container_of 宏和 offsetof 宏分析

    相关文章

      网友评论

          本文标题:C语言基础之关键词

          本文链接:https://www.haomeiwen.com/subject/vtkzrdtx.html