关于C/C++字节对齐、位域、大小端、柔性数组问题

目录

一、字节对齐

1.概念

2.原则

3.建议

二、位域

1.概念

2.定义形式

3.对位域的赋值

三、大小端

1.概念(有趣的出处:格利佛游记鸡蛋问题)

2.大小端的出现原因

3.各自优势

四、柔性数组

1.概念

2.用法

3.说明


一、字节对齐

1.概念

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。

2.原则

①成员变量的顺序会影响结构体的大小。

一般情况下,成员变量所占用的空间,会被其中最宽变量类型所框定,而当定义小于最宽类型的成员变量时,这个变量会和相邻的成员变量合并,拼为成员变量的整数倍形式,如果相邻处没有合适的变量,它将自身占有最宽类型成员变量存储空间大的大小。

②结构体大小是最宽字节类型的整数倍

当用上述规则束缚成员变量的大小时,成员变量自然是最宽字节类型的整数倍。

3.建议

①编译器对于对齐方式是可以选择的。

②如果有相同类型的变量,一定要放在一起,会减少结构体的空间。

这样设置就是为了让小于最宽类型的成员变量能够合并,减少空间浪费。

③结构体定义,变量类型从小到大的顺序定义合适。

此种定义方式让人更容易理解,也提高代码的整洁性。

④#program pack()可以设置对齐方式。

 

 

 

二、位域

1.概念

有些信息在存储时,并不需要占用一个完整的字节,而只需要几个或一个二进制位。为了节省存储空间,并使处理简便,c语言提出了位域。

位域:把一个字节中的二进制位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名

2.定义形式

struct 位域结构名

{位域列表};

位域列表的形式为:类型说明符 位域名:位域长度

注意:①一个位域不允许占两个字节,因此一个位域的长度不能大于一个字节(8位二进制位)的长度。

3.对位域的赋值

①eg.  bit.a=1;

② eg. pbit=&bit;  pbit->a=1;

 

 

 

三、大小端

1.概念(有趣的出处:格利佛游记鸡蛋问题)

CPU大端存储模式:数据的低位保存在内存的高地址中,数据的高位保存在内存的低地址中。

CPU小端存储模式:数据的低位保存在内存的低地址中,数据的高位保存在内存的高地址中。

2.大小端的出现原因

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122(左高右低),那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

3. 网络字节序与主机字节序的转换

由于网络字节序一律为大端,而目前个人PC大部分都是X86的小端模式,因此网络编程中不可避免得要进行网络字节序和主机字节序之间的相互转换,下面是 socket 提供的转换函数。

#define ntohs(n)     // 16位数据类型网络字节顺序到主机字节顺序的转换  
#define htons(n)     // 16位数据类型主机字节顺序到网络字节顺序的转换  
#define ntohl(n)     // 32位数据类型网络字节顺序到主机字节顺序的转换  
#define htonl(n)     // 32位数据类型主机字节顺序到网络字节顺序的转换

4.各自优势

 

(越小越顺畅)

4.示例

地址小端存放内容大端存放内容
0x080040030x120x78
0x080040020x340x56
0x080040010x560x34
0x080040000x780x12

 

 

 

四、柔性数组

1.概念

为了实现在结构体中存放长度是动态的字符串,柔性数组是两种做法之一,它为了解决使用数组时内存的冗余和数组的越界问题。

2.用法

①定义语句:eg. char a[];      空间申请语句: Test *t=(Test*)malloc(sizeof(Test)+sizeof(char)*(10+1));

②由于申明内存连续性的关系,柔性数组成员必须定义在结构体的最后一个,并且不能是唯一的成员。

3.说明

数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针!),但对于这个数组的大小,我们可以进行动态分配,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值