C 位字段,_Alignas关键字,可变参数函数和高级数据结构

本文介绍了C语言中的位字段、_Alignof和_Alignas关键字,以及可变参数函数的使用。接着探讨了四种高级数据结构:双向链表、HashMap、FIFO队列和红黑树的实现与应用。对于位字段,讲解了其在内存管理和节省存储空间上的作用;在内存对齐方面,解释了_Alignof和_Alignas如何影响变量对齐;最后,通过代码示例展示了如何在C语言中实现这些高级数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、位字段

二、_Alignof和_Alignas关键字

三、可变参数函数

四、高级数据结构

1、双向链表

2、HashMap

3、FIFO队列

4、红黑树


一、位字段

    位字段是C语言提供的操作位的一种便捷且代码可读性更好的方式,适用于只需少量的位表示数据的场景下。GNU C下,位字段的内存大小是unsigned int类型所占内存的整数倍,64位下unsigned int类型通常是4字节,32位,即位字段最小为4字节,编译器保证位字段的内存大小大于位字段中声明的内存大小。

#include <stdio.h>
#include <stdbool.h>


//声明位字段,数字表示该字段占的位数,未命名的字段用于填充的
//位字段在内存中以unsigned int的内存大小为基本布局单位,64位下通常是4字节,32位,
//即使位字段声明的总位数小于32位,也会占用4字节内存,如果大于32位则会自动扩充位字段的
//内存大小,但保证按照4字节对齐
struct box_props {
    bool b1                 : 1;
    unsigned int b10     : 10;
//    unsigned int                : 4;
    unsigned int                : 24;
    unsigned int b3   : 3;
    unsigned int b2   : 2;
    unsigned int                : 2;
};


int main(void)
{
	printf("unsigned int size:%d \n",sizeof(unsigned int));
	printf("box_props size:%d \n",sizeof(struct box_props));

	//位字段的使用跟正常的结构体一致
    struct box_props a={1,345,7,3};
    printf("a b1:%d\n",a.b1);
    printf("a b10:%d\n",a.b10);
    printf("a b3:%d\n",a.b3);
    printf("a b2:%d\n",a.b2);
    
    //对位字段赋值时,需要确保数值不能大于该字段对应位数允许的最大值,这里是1024,超过后编译器会自动截断掉高位
    //1025的二进制是1000 0000 01,截掉高位1,就是000 0000 01
    a.b10=1025;
    printf("a b10:%d\n",a.b10);

    return 0;
}

二、_Alignof和_Alignas关键字

     _Alignof给出指定数据类型内存对齐的字节数,如double按8字节对齐,其内存地址都是8的整数倍。_Alignas关键字指定某个变量按照其他数据类型对齐,如char正常按1字节对齐,可指定按short类型的2字节对齐。

#include <stdio.h>
int main(void)
{
    int dx;
    char ca;
    char cx;
    //指定对齐的字节数必须大于本来的,这里必须大于4
//    int _Alignas(short)  dz;
    int _Alignas(double)  dz;
    char cb;
    //_Alignas要求某个变量的内存地址按指定的字节数对齐
    char _Alignas(short)  cz;
   
    //_Alignof关键字给出该类型变量的内存对齐字节数,比如double按8字节对齐,即其存储地址必须是8的整数倍
    printf("char alignment:   %zd\n", _Alignof(char));
    printf("short alignment: %zd\n", _Alignof(short));
    printf("int alignment: %zd\n", _Alignof(int));
    printf("double alignment: %zd\n", _Alignof(double));
    printf("&dx: %p\n", &dx);
    printf("&ca: %p\n", &ca);
    printf("&cx: %p\n", &cx);
    printf("&dz: %p\n", &dz);
    printf("&cb: %p\n", &cb);
    printf("&cz: %p\n", &cz);
    
    return 0;
}

三、可变参数函数

      C语言通过stdarg.h头文件提供了对可变参数函数的支持,即函数的参数的个数和类型是未知的,不过要求可变参数必须是最后一个参数,且可变参数前一个参数固定是int类型的,固定用于表示实际参数个数。

#include <stdio.h>
//必须引入这个头文件
#include <stdarg.h>
double sum(int, ...);

int main(void)
{
    double s,t;
    
    s = sum(5, 1.1, 2.5, 13.3,1,2,'c');
    t = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1);
    printf("return value for "
           "sum(3, 1.1, 2.5, 13.3,1,2,'c'):                %g\n", s);
    printf("return value for "
           "sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1): %g\n", t);
    
    return 0;
}

double sum(int lim,...)
{
	//保存可变参数的列表
    va_list ap;
    double tot = 0;
    int i;
    
    //将实际参数放到列表中
    va_start(ap, lim);
    for (i = 0; i < lim; i++){
    	//返回指定类型的参数,实际参数类型不符则返回0
    	double a=va_arg(ap, double);
    	printf("va_arg i=%d,a=%f\n",i,a);
        tot += a;
    }
    //清空参数列表
    va_end(ap);
    
    return tot;
}

四、高级数据结构

    提供类型属性和相关操作的抽象描述被称为抽象数据类型(ADT),通俗的理解就是Java中的类,既有类属性也有关联的类方法,类方法通过接口的形式定义,使用方只关心接口定义不关心接口实现。

1、双向链表

     C中typedef不允许重复定义,因此只能通过void指针加上指针类型强转这种方式实现泛型的效果,最终让链表能够适用于所有数据类型。

头文件即接口定义如下:

//避免头文件重复引入
#ifndef MYLIST_H_INCLUDED
#define MYLIST_H_INCLUDED
#include <stdio.h>


typedef struct myNode
{
	//用void指针实现泛型效果
    void * data;
    struct myNode *next;
} MyNode;

typedef struct myList
{
    MyNode * first;
    MyNode * last;
    int count; //链表总结点数
    int (*equal)(void * a, void * b);
} MyList;

typedef struct myListIterator
{
    MyNode * p;
    int count; //当前遍历的链表节点索引
    int allSize; //链表节点总数
} MyListIterator;

//创建链表
MyList * createMyList();

//创建链表,带有相等参数,用于查找
MyList * createMySearchList(int(*equal)(void * a, void * b));

//释放链表
void freeMyList(MyList * list);

//插入在尾部
void myListInsertDataAtLast(MyList* const list, void* const data);

//插入在首部
void myListInsertDataAtFirst(MyList * const list, void* const data);

//插入
void myListInsertDataAt(MyList * const list, void* const data, int index);

//删除在尾部
void* myListRemoveDataAtLast(MyList* const list);

//删除在首部
void* myListRemoveDataAtFirst(MyList * const list);

//删除
void* myListRemoveDataAt(MyList* const list, int index);

//删除对象,返回是否删除成功
int myListRemoveDataObject(MyList* const list,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值