Day 14 结构体 3.30

#include <stdio.h>

struct S1
{
	char c1;//1字节
	int i;//4字节
	char c2;//1字节
};

struct S2
{
	char c1;//1字节
	char c2;//1字节
	int i;//4字节
};

int main()
{
    struct S1 s;
    struct S2 s2;    
    printf("%d\n",sizeof(s)):
    printf("%d\n",sizeof(s2)):
    //结果s的大小为12,s2的大小为8
}

struct S3
{
	double d;
	char c;
	int i;
};//16

struct S4
{
	char c1;//1
	struct S3 s3;//16
	double d;//8
};

结构体内存对齐

结构体第一个成员放置在偏移量为0的地址处。

其他数字要对齐到对齐数的整数倍地址处,对齐数=编译器默认的一个对齐数与该成员大小的较小值。vs中对齐数默认为8,linux环境下没有默认对齐数。就是看8和成员类型的大小,对齐到较小的数的整数倍。

最后结构体的大小要为最大成员类型的整数倍。

12就是这么来的。

同理s2

如果在设计结构体的时候既想节省空间,又满足对齐,可以把占用空间小的成员放置在一起。

offsetof - 宏

包含在头文件<stddef.h>中。
计算结构体成员相对于起始位置的偏移量的。


int main()
{
	printf("%u\n", offsetof(struct S3, d));
	printf("%u\n", offsetof(struct S3, c));
	printf("%u\n", offsetof(struct S3, i));
}

修改默认对齐数

#pragma pack(1)
struct S
{
	char c;//1
	double d;//8
};
#pragma pack()

int main()
{
	struct S s;
	printf("%d\n", sizeof(s));
	return 0;
}

使用以下代码:

#pragma pack()

来修改默认对齐数,括号内写想设置的默认对齐数。

位段

位段的声明和结构很相似,但是有区别。

1.位段成员必须是int ,unsigned int 或者signed int。

2.位段的成员后面还有一个冒号和一个数字。

struct A
{
    char a : 3 ; //2代表_a这个成员所占内存比特位。
    char b : 4 ;
    char c : 5;
    char d : 4;
};

int main()
{
    struct S s = {0};
    printf("%d",sizeof(A)); //结果只占三个字节。
    s.a=10;
    s.b=12;
    s.c=3;
    s.d=4;
    return 0;
}

 位段的跨平台问题:

1.int位段被当成有符号还是无符号数不确定。

2.位段中最大位数目不确定(16位机器最大16,32位最大32)

3.位段中成员在内存中从左向右分配还是从右向左分配未定义。

4.当一个结构保护你两个位段,第二个位段成员较大,无法容纳于第一个位段剩余的位时,是继续用空比特位还是舍弃空比特位不确定。

枚举

enum Color
{
	RED,     //默认初始化成0,往下递增,
	GREEN,   // 因此这里就是1。
	BLUE
};

enum Color
{
	RED=5,   //这样的话往下递增,Green就是6。     
	GREEN,   
	BLUE
};

//#define RED 5

//define也可以定义常量,枚举更具有代码可读性,有类型检查,更加严谨。防止了命名污染等等。

int main()
{

	enum Color d = RED; //RED尽量不要写成5,避免编译器类型检查。 
    //RED=6; 这么写是错误的。
	printf("%d\n", RED);

	return 0;
}

联合(共用体)

也是一种特殊的自用体。
 

union Un
{
	char c;//1
	int i;//4
};

int main()
{
	union Un u;
	u.c = 0x55;
	u.i = 0;
	printf("%d\n", sizeof(u)); //结果为4。

	printf("%p\n", &u);
	printf("%p\n", &(u.c));
	printf("%p\n", &(u.i)); //三个地址相同。因为i和c有一处字节共用。因此改一处都会改。

	return 0;
}

用联合来判断大小端:

int check_sys()
{
	union Un
	{
		char c;
		int i;
	}u;
	u.i = 1;

	return u.c;//
}

int main()
{
	if (1 == check_sys())
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}

    //原判断方法。
	//int i = 1;
	//01 00 00 00
	/*if (1 == *(char*)&i)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}*/
	return 0;
}

联合体大小计算:

union Un
{
	char arr[5];//5
	int i;//4
};

int main()
{
	printf("%d\n", sizeof(union Un)); //结果为8。
    //联合体大小不一定是最大成员大小,可能会存在空内存来补齐最大对齐数整数倍。

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值