结构体柔性数组_位域

1. struct中函数

结构体中函数占用字节数:32位主机占用4个字节,64位主机占用8个字节。

结构体中函数本质是指针,占用字节数与指针相同。

#include <stdio.h>

struct student_st {
        char name[20];
        int no;
        void (*show)(struct student_st);
        void (*show1)(struct student_st);
};

struct func_st{
        void (*print)();
};

void show(struct student_st st)
{
        printf("name: %s, no: %d\n", st.name, st.no);
}

int main(int argc, char *argv[])
{
        printf("student struct size = %d\n", sizeof(struct student_st));
        printf("func struct size = %d\n", sizeof(struct func_st));

        struct student_st st = {"wang", 1, show};

        st.show(st);

        return 0;
}

2. 柔性数组

C99中,柔性数组成员允许结构中包含一个大小可变的数组,但结构中的柔性数组成员前面必须至少一个其他成员。Sizeof返回的这种结构大小不包含柔性数组的内存。

包含柔性数组的结构可用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

注:柔性数组不能直接定义,然后仅malloc柔性数成员,应整体mallo分配空间。

柔性数组分配内存
柔性数组结构体size

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(2) //设置2字节对齐
struct student 
{
	unsigned char anticollision_front:1;
	unsigned char anticollision_back:1;
	unsigned char charge_detect:1;
	unsigned char sw_a:1;
	unsigned char sw_b:1;
	short no;
	int id;
	char name[];
};

int main()
{
	printf("sizeof int is %ld\n", sizeof(int));
	printf("sizeof struct student is %ld\n", sizeof(struct student));
	
#if 0  // error: invalid use of flexible array member: st.name =(char *)malloc(6);
	struct student st;
	st.no = 1;
	st.id = 1;
	st.name =(char *)malloc(6);
	if(st.name == NULL){
		printf("malloc error!\n");
		exit(-1);
	}
	strcpy(st.name, "WORLD");
	printf("st.no[%d], st.id[%d], st.name[%s]\n", st.no, st.id, st.name);
#endif

	struct student *pst;
	int ssize = sizeof(struct student) + 6*sizeof(char);
//	pst = (struct student*)malloc(sizeof(struct student) + 6*sizeof(char));
	pst = (struct student*)malloc(ssize);
	if(pst == NULL){
		printf("malloc error!\n");
		exit(-1);
	}
	pst->no = 1;
	pst->id = 1;
	pst->anticollision_front=0;
	pst->anticollision_back=1;
	pst->charge_detect = 1;
	pst->sw_a = 0;
	pst->sw_b = 1;
	strcpy(pst->name, "WORLD");
	printf("pst->no[%d], pst->id[%d], pst->name[%s]\n", pst->no, pst->id, pst->name);
	printf("pst->anticollision_front[%u], pst->anticollision_back[%u], pst->charge_detect[%u], 
                pst->sw_a[%u], pst->sw_b[%u]\n", pst->anticollision_front, pst->anticollision_back, 
                pst->charge_detect, pst->sw_a, pst->sw_b);
	printf("sizeof struct student is %ld\n", sizeof(struct student));
	
	int i;
	char *pc = (char *)pst;
	for(i = 0; i <ssize;){
		printf("%.2X ", (char)pc[i]&0xFF);
		i++;
	}
	printf("\n");

	struct student *pst1 = (struct student*)malloc(ssize);
	if(pst1 == NULL){
		printf("malloc error!\n");
		exit(-1);
	}
	memcpy(pst1, pst, ssize);
	pc = (char *)pst1;
	for(i = 0; i <ssize;){
		printf("%.2X ", (char)pc[i]&0xFF);
		i++;
	}
	printf("\n");

	free(pst);
	free(pst1);
	return 0;
}

3. 位域

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

定义

位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

struct 位域结构名 
{
    位域列表
};
其中位域列表的形式为: 类型说明符 位域名:位域长度 

例如:

struct bs 
{ 
int a:8; 
int b:2; 
int c:6; 
}; 

注意

对于位域的定义尚有以下几点说明:

  1. 一个位域必须存储在同一个字节中,不能跨两个字节。

如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

struct bs 
{ 
    unsigned a:4 
    unsigned :0 /*空域*/ 
    unsigned b:4 /*从下一单元开始存放*/ 
    unsigned c:4 
} 

这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

  1. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k 
{ 
    int a:1 
    int :2 /*该2位不能使用*/ 
    int b:3 
    int c:2 
}; 

从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。
也就是说后面加上“:1”的意思是这个成员的大小占所定义类型的1 bit,“:2”占2 bit,依次类推。当然大小不能超过所定义类型包含的总bit数。

参考:结构体中冒号--位域

posted @ 2016-11-21 00:25  yuxi_o  阅读(708)  评论(0编辑  收藏  举报