结构体字节对齐packed

合集下载

C语言的字节对齐及#pragmapack的使用

C语言的字节对齐及#pragmapack的使用

C语言的字节对齐及#pragmapack的使用C编译器的缺省字节对齐方式(自然对界)在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。

在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。

各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插入的空字节),第一个成员的地址和整个结构的地址相同。

C编译器缺省的结构成员自然对界条件为“N字节对齐”,N即该成员数据类型的长度。

如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。

若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。

C编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。

若结构体各成员长度之和不为“结构整体自然对界条件的整数倍,则在最后一个成员后填充空字节。

例子1(分析结构各成员的默认字节对界条界条件和结构整体的默认字节对界条件):struct Test{char x1; // 成员x1为char型(其起始地址必须1字节对界),其偏移地址为0char x2; // 成员x2为char型(其起始地址必须1字节对界,其偏移地址为1float x3; // 成员x3为float型(其起始地址必须4字节对界),编译器在x2和x3之间填充了两个空字节,其偏移地址为4char x4; // 成员x4为char型(其起始地址必须1字节对界),其偏移地址为8};因为T est结构体中,最大的成员为flaot x3,因些此结构体的自然对界条件为4字节对齐。

则结构体长度就为12字节,内存布局为1100 1111 1000。

例子2:#include <stdio.h>//#pragma pack(2)typedef struct{int aa1; //4个字节对齐 1111char bb1;//1个字节对齐 1short cc1;//2个字节对齐 011char dd1; //1个字节对齐 1} testlength1;int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12typedef struct{char bb2;//1个字节对齐 1int aa2; //4个字节对齐 01111short cc2;//2个字节对齐 11char dd2; //1个字节对齐 1} testlength2;int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011 1111 1000,length = 12typedef struct{char bb3; //1个字节对齐 1char dd3; //1个字节对齐 1int aa3; //4个字节对齐 001111short cc23//2个字节对齐 11} testlength3;int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12typedef struct{char bb4; //1个字节对齐 1char dd4; //1个字节对齐 1short cc4;//2个字节对齐 11int aa4; //4个字节对齐 1111} testlength4;int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8int main(void){printf("length1 = %d.\n",length1);printf("length2 = %d.\n",length2);printf("length3 = %d.\n",length3);printf("length4 = %d.\n",length4);return0;}改变缺省的对界条件(指定对界)· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。

c语言结构体中的数组字节对齐

c语言结构体中的数组字节对齐

C语言结构体中的数组字节对齐在C语言中,结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起。

结构体中常常包含多个成员变量,其中可能有数组类型的成员变量。

在结构体中使用数组时,需要了解数组字节对齐的概念和规则,以确保内存的最佳利用和访问的效率。

什么是字节对齐字节对齐是指在将数据存储在计算机内存中时,按照特定规则进行调整,以确保数据的存储和访问的效率。

字节对齐的规则可以对齐数据的起始地址或者数据的长度。

计算机中的数据存储是按照字节(Byte)来划分的,一个字节通常由8个二进制位组成。

字节对齐的主要目的是为了节省内存和提高访问效率。

在C语言中,结构体中的成员变量通常按照字节对齐的规则来排列。

C语言结构体中的数组字节对齐规则在C语言中,结构体中的数组字节对齐规则通常遵循以下原则:1.结构体的起始地址必须是所有成员变量所要求对齐方式的最小公倍数。

2.结构体中的每个成员变量的地址必须是它本身的大小的整数倍。

3.结构体的总大小必须是其最大成员变量大小的整数倍。

根据字节对齐规则,如果结构体中的成员变量的累计大小不是字节对齐的倍数,编译器会在成员变量之间添加填充字节,以满足对齐要求。

这些填充字节在结构体的占用空间中不可访问。

填充字节的目的是将后续成员变量的地址对齐,以提高内存访问效率。

数组字节对齐的示例为了更好地理解数组字节对齐的规则,我们来看一个示例。

#include <stdio.h>struct MyStruct {char c;int i;char arr[3];};int main() {struct MyStruct s;printf("sizeof(MyStruct) = %lu\n", sizeof(struct MyStruct));printf("sizeof(s.c) = %lu\n", sizeof(s.c));printf("sizeof(s.i) = %lu\n", sizeof(s.i));printf("sizeof(s.arr) = %lu\n", sizeof(s.arr));return 0;}输出结果:sizeof(MyStruct) = 12sizeof(s.c) = 1sizeof(s.i) = 4sizeof(s.arr) = 3在这个示例中,我们定义了一个包含一个字符类型变量、一个整型变量和一个长度为3的字符数组的结构体MyStruct。

02_32位和64位系统下int、char、long、double所占的内存以及内存字节对齐问题

02_32位和64位系统下int、char、long、double所占的内存以及内存字节对齐问题

02_32位和64位系统下int、char、long、double所占的内存以及内存字节对齐问题32位和64位系统下 int、char、long、double所占的内存以及内存字节对齐问题 8字节为上限C类型30位机器(字节)64位机器(字节)char11short22int44long int48long long88char *48float44double88#include<stdio.h>struct A{int a;char b;double c;char d;};struct B{char a;double b;char c;};int main(){printf("int =%lu,char=%lu,double=%lu\n",sizeof(int),sizeof(char),sizeof(double));printf("structA=%lu structB=%lu\n",sizeof(struct A),sizeof(struct B));return0;}//64位最多可以8位字节对齐(先4位,遇8位变8位对齐)//32位最多可以4位字节对齐//64位编译输出:int =4,char=1,double=8structA=24 structB=24// structA: 4+(1+3)+8+(1+7) = 24// structB: (1+7)+8+(1+7) = 24//未遇到8位数据类型时时4字节对齐,遇到8字节数据类型变为8字节对齐//32位编译输出:int =4,char=1,double=8structA=20 structB=16// struct A : 4+(1+3)+8+(1+3) = 20// struct B : (1+3)+8+(1+3) = 16//不管怎么样都只能是4字节对齐结构体字节对齐问题: 未进⾏特殊说明时,按照结构体中size最⼤成员对齐 当进⾏对应字节对齐说明后,按照说明要求字节对齐阿秀笔记: c++11以后引⼊两个关键字 alignas与 alignof。

stm32中使用#pragma pack(非常有用的字节对齐用法说明)

stm32中使用#pragma pack(非常有用的字节对齐用法说明)

#pragma pack(4) //按4字节对齐,但实际上由于结构体中单个成员的最大占用字节数为2字节,因此实际还是按2字节对齐typedef struct{char buf[3];//buf[1]按1字节对齐,buf[2]按1字节对齐,由于buf[3]的下一成员word a是按两字节对齐,因此buf[3]按1字节对齐后,后面只需补一空字节word a; //#pragma pack(4),取小值为2,按2字节对齐。

}kk;#pragma pack() //取消自定义字节对齐方式对齐的原则是min(sizeof(word ),4)=2,因此是2字节对齐,而不是我们认为的4字节对齐。

这里有三点很重要:1.每个成员分别按自己的方式对齐,并能最小化长度2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度3.对齐后的结构体整体长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐补充一下,对于数组,比如:char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐.如果写: typedef char Array3[3];Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度.不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个.声明:整理自网络达人们的帖子,部分参照MSDN。

作用:指定结构体、联合以及类成员的packing alignment;语法:#pragma pack( [show] | [push | pop] [, identifier], n )说明:1,pack提供数据声明级别的控制,对定义不起作用;2,调用pack时不指定参数,n将被设成默认值;3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降;语法具体分析:1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment 数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop 直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack 中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。

字节对齐的具体方法

字节对齐的具体方法

字节对齐的具体方法
字节对齐的方法有以下两种:
1.结构体总的大小要是其成员中最大size的整数倍,如果不是编译器会在其末尾添加填充字节(trailing padding)。

2.指定对齐方式,使用以下方式声明:#pragmapack(4),结构体第一个成员的地址和结构体的首地址相同,结构体每个成员的地址偏移需要满足:N大于等于该成员的大小,那么该成员的地址偏移需满足默认对齐方式(地址偏移是其成员大小的整数倍);N小于该成员的大小,那么该成员的地址偏移是N的整数倍。

结构体总的大小需要时N的整数倍,如果不是需要在结构体的末尾进行填充。

如果N大于结构体成员中最大成员的大小,则N不起作用,仍然按照默认方式对齐。

需要注意的是:在使用#pragma pack设定对齐方式一定要是2的整数幂,也就是(1,2,4,8,16,…),不然不起作用的,仍然按照默认方式对齐。

结构体字节对齐最简单的解释

结构体字节对齐最简单的解释

有效对齐值与以下两种对齐值有关
1、 自身对齐值
对于单一变量,自身对齐值就是该变量所占的内存大小。
对于结构体变量,自身对齐值就是结构体成员自身对齐值中最 大的一个。
2、 指定对齐值
用程序自定对齐值。
#pragma pack(2)
//开始
#pragma pack()
//结束
代表指定 2 字节对齐
如果没有指定对齐值,那么有效对齐值就是变量的自身对齐值;如果指 定对齐值,那么有效对齐值就是这两个对齐值中的小者。
由以上说明就可以知道一个结构体变量所占的真实字节数了。
下例中所有结构体的起始地址都假设从 0 开始
例 1:
struct a
{
char no[10]; //没有指定对齐值,所有有效对齐值为自身对齐值,即
1;所以占用地址 0--9
int p;
//没有指定对齐值,所有有效对齐值为自身对齐值,即 4;
所以占用地址 12--15
long int pp; //没有指定对齐值,所有有效对齐值为自身对齐值,即
4;所以占用地址 16--19
unsigned int ppp;// 没有指定对齐值,所有有效对齐值为自身对齐
值,即 4;所以占用地址 20--23
char x; //没有指定对齐值,所有有效对齐值为自身对齐值,即 1;
所以占用地址 24
个成员结束后,所占的内存空间大小已经是有效对齐值的
整数倍了,所以不需要再加上填充字节了。
} xy;
例 2: struct S1 { char c; int i; }; struct S3 { char c1; S1 s; char c2; };
//占 8 字节 //占 16 字节

C语言的位域,字节对齐

C语言的位域,字节对齐

C的位域(bit fields )struct bs{int a:7;int b:2;int c:1;};表示用一个整数的前8位表示a,用一个整数的2位表示b,用一个整数的1位的来表示c,位域定义不能超过数据定义类型的最大位,如struct {char a:9; //char 最大值为8位int b:33; //int 的最大值为32,不能超过其中定义值}位域有如下特殊定义,1)只要不超过数据定义最大值,多个位域可以定义一个数据单位里,如下是合法,定义,也是常用定义Struct PC_PIN{Char bit0:1,bit1:1,Bit2:1,Bit3:1,Bit4:1,Bit5:1,Bit6:1,Bit7:1;}2)位域可以采用’匿名',定义,这样程度就不能使用这些位,这样定义纯粹是起占位用.struct foo1 {int a : 1;int : 2;short c : 1;};上例中,在a和c中有一个2位的匿名占位struct bs{unsigned a:4unsigned :0 /*空域*/unsigned b:4 /*从下一单元开始存放*/unsigned c:4}在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

位域占位计算有点复杂1.定义位域不足一个数据位的,按一个完整数据算Struct tagA{Int a:3;Int b;};Sizeof()值是8,因为a仍然按4位来核算.2.如果连续定义几点相同类型.而位域总合不超过类型总位数长度的,会被编译器设为一个合并为一个位域定义如struct tagA{int a:1;int b:2;int c;3}等同于struct tagB{Int a:1,b:2,c:3;};Sizeof()的长度都是4,因为tagA的各个成员加起长度都没有超过32,所以仍然为43.aaa位域的被广泛应用于8位单片机编程中.因为一个8位寄存器刚好是一个char 的宽度,因为可以定义一个8个位位域来对寄存器的各个位进行存取.这样程序比较简单并且好理解.但在32位CPU应用反而不广泛,因为32CPU的寄存器是为32位宽度,正好是一个int 的宽度,但int 在不同CPU中的表示顺序位是不一致的.在不同字节序CPU里定义的位域,有一些不样,换句话说,定义这样位域需要定义两套类型.如ip的头定义.struct iphdr {#if defined(__LITTLE_ENDIAN_BITFIELD)__u8 ihl:4,version:4;#elif defined (__BIG_ENDIAN_BITFIELD)__u8 version:4,ihl:4;#else#error "Please fix <asm/byteorder.h>"#endif__u8 tos;__u16 tot_len;__u16 id;__u16 frag_off;__u8 ttl;__u8 protocol;__u16 check;__u32 saddr;__u32 daddr;/*The options start here. */};使用反而不如位操作定义方便,因此32位CPU使用位域有一些麻烦字节对齐现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但为为了CPU访问数据的快速,通常都要求数据存放的地址是有一定规律的.比如在32位CPU上,一般要求变量地址都是基于4位,这样可以保证CPU用一次的读写周期就可以读取变量.不按4位对齐,如果变量刚好跨4位的吗,这样需要CPU两个读写周期.效率自然低下.因此,在现代的编译器都会自动把复合数据定义按4位对齐,以保证CPU 以最快速度读取,如下例(gcc version 编译器(32位x86平台))struct A {int a;char b;short c;};结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short 型数据一个。

结构体字节对齐的方法

结构体字节对齐的方法

结构体字节对齐的方法全文共四篇示例,供读者参考第一篇示例:结构体字节对齐是编程中一个非常重要的概念,尤其在涉及到内存对齐的底层编程中更是不可或缺。

在结构体的定义中,每个元素都需要在内存中占用一定的空间,而结构体整体的大小受到字节对齐规则的限制。

本文将介绍结构体字节对齐的方法及其原理,希望能帮助读者更好地理解和掌握这一概念。

一、什么是字节对齐字节对齐是指在结构体中每个元素按照特定的规则分配内存空间,以便提高内存读取的效率。

在计算机系统中,一般要求数据在内存中的存储地址是某个特定值的倍数,这个特定值就是对齐系数。

常用的对齐系数有1、2、4、8等,根据不同的系统和编译器,对齐系数可能会有所不同。

二、结构体字节对齐的原理在C语言中,结构体的内存对齐是通过编译器来进行处理的。

当定义一个结构体时,编译器会按照一定的规则对结构体中的元素进行字节对齐,以便提高读取效率。

具体的对齐规则如下:1. 结构体中每个元素的偏移量必须是它自身类型大小的整数倍。

2. 结构体的大小必须是最大元素类型大小的整数倍。

3. 结构体的对齐系数为结构体中所有元素类型大小的最大值。

通过这些规则,编译器可以在编译时确定结构体的大小,并根据对齐系数进行内存对齐,从而提高内存访问的效率。

1. 使用#pragma pack指令在C语言中,可以使用#pragma pack指令来改变编译器默认的对齐系数。

通过指定pack(n)来设置n值,表示结构体的对齐系数为n。

这样可以在需要的时候自定义结构体的对齐系数,提高程序的效率。

```c#pragma pack(1)struct Student {char name[10];int age;float score;};```上面的代码中,通过#pragma pack(1)改变了结构体的对齐系数为1,从而可以确保结构体中的每个元素都按照一个字节进行对齐。

2. 使用__attribute__((packed))关键字在GCC编译器中,可以使用__attribute__((packed))关键字来实现对齐系数的设置。

c语言中的结构体对齐 -回复

c语言中的结构体对齐 -回复

c语言中的结构体对齐-回复C语言中的结构体对齐是指编译器如何对结构体中的成员进行内存对齐的规定。

结构体的对齐有助于提高内存读取速度和数据访问的效率,特别是在计算机中有硬件对齐要求的情况下更为重要。

在C语言中,结构体是一种自定义数据类型,可以包含不同类型的成员变量。

通过结构体可以将多个关联的数据项组合在一起,方便操作和管理。

在创建结构体时,编译器为每个结构体成员分配内存空间,并将它们按一定的规则进行排列,以提高访问效率。

结构体对齐的原理是为了让结构体成员在内存中对齐到特定的地址,以便于CPU的读取。

这样可以减少CPU访问内存的次数,并且避免因为访问未对齐的数据而导致的性能下降或错误。

在默认的情况下,C语言的结构体对齐规则遵循以下原则:1. 对齐基本单位的大小:编译器会判断基本数据类型的大小,并将结构体成员对齐到其大小的整数倍。

例如,一个int类型的成员变量通常会被对齐到4字节边界,而一个double类型的成员变量通常会被对齐到8字节边界。

2. 对齐规则的字节对齐方式:编译器会根据系统的要求和硬件对齐要求,选择合适的字节对齐方式。

通常情况下,32位系统要求按4字节对齐,64位系统要求按8字节对齐。

3. 对齐顺序:结构体成员的排列顺序也会影响对齐规则。

编译器会尽可能地将占用空间较小的成员放在前面,并将占用空间较大的成员放在后面,以避免空洞和浪费空间。

因为不同的编译器和操作系统可能有不同的对齐要求,所以结构体的对齐规则可能会有所差异。

为了保证结构体在不同平台上的兼容性,可以使用特定的编译指令来控制结构体的对齐方式。

在C语言中,可以使用pragma pack预处理指令来设置结构体的对齐方式。

这个指令用于告诉编译器修改结构体对齐规则的默认值。

例如,可以使用pragma pack(1)指令将对齐方式设置为按1字节对齐,或者使用pragma pack(4)指令将对齐方式设置为按4字节对齐。

pragma pack指令的使用方法如下所示:cpragma pack([alignment])其中,alignment表示对齐方式的参数值。

C语言字节对齐__align()讲解

C语言字节对齐__align()讲解
00现代计算机中内存空间都是按照byte划分的从理论上讲似乎对任何类型的变量的访问可以从任何地址开始但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问这就需要各种类型数据按照一定的规则在空间上排列而不是顺序的一个接一个的排放这就是对齐
ls/6729724#comments ,方便大家参考学习
struct test { char x1; short x2; float x3; char x4; }; #pragma pack() //取消1字节对齐,恢复为默认4字节对齐 这时候 sizeof(struct test)的值为8。 例3 #define GNUC_PACKED __attribute__((packed)) struct PACKED test { char x1; short x2; float x3; char x4; }GNUC_PACKED; 这时候 sizeof(struct test)的值仍为8。 二、深入理解 什么是字节对齐,为什么要对齐? TragicJun 发表于 2006-9-18 9:41:00 现代计算机中内存空间都是按照 byte 划分的,从理 论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变 量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排 列,而不是顺序的一个接一个的排放,这就是对齐。
sizeof(struct D)值为7。
后面我们再讲解#pragma pack()的作用.
三.编译器是按照什么样的原则进行对齐的?
先让我们看四个重要的基本概念:
1.数据类型自身的对齐值: 对于 char 型数据,其自身对齐值为1,对于 short 型为2,对于 int,float,double

结构体字节对齐的作用

结构体字节对齐的作用

结构体字节对齐的作用
结构体字节对齐是编程中非常重要的一个概念,它的作用有以下几点:
1. 提高内存使用效率:结构体中的成员变量有可能会因为字节对齐的原因而造成浪费,但是字节对齐可以让结构体中的成员变量按照一定的规则排列,从而减少浪费的空间,提高内存使用效率。

2. 保证结构体成员变量的访问速度:由于结构体中的成员变量是按照一定的规则排列的,所以它们的内存地址是连续的,这样就可以提高结构体成员变量的访问速度。

3. 避免内存错误:如果结构体中的成员变量没有经过字节对齐,那么在访问某个成员变量时,可能会访问到不属于该成员变量的内存区域,从而导致内存错误。

而字节对齐可以避免这种情况的发生。

总的来说,结构体字节对齐在编程中是非常重要的,它可以提高内存使用效率、保证结构体成员变量的访问速度,同时也可以避免内存错误的发生。

- 1 -。

__attribute__用法

__attribute__用法

__attribute__用法在C语言中,__attribute__是一种特殊的语法,用于给函数、变量、结构体等对象添加属性。

它可以用于告诉编译器一些额外的信息,帮助编译器进行优化或者进行静态检查。

在本文中,我们将对__attribute__的使用方法进行详细解析,并介绍一些常用的属性。

1. __attribute__((packed))__attribute__((packed))可以用于结构体或者联合体,它告诉编译器不要对结构体进行字节对齐。

在默认情况下,编译器会对结构体进行字节对齐,以提高读写效率。

但是在一些特殊情况下,我们需要按照实际占用的字节数来定义结构体,这时就可以使用packed属性。

例如,我们定义一个结构体来表示一个位域:```struct BitField {unsigned int a : 1;unsigned int b : 2;unsigned int c : 3;} __attribute__((packed));```在上面的例子中,由于使用了packed属性,结构体BitField的大小将是6个字节,而不是按照默认的对齐方式4个字节。

2. __attribute__((aligned(n)))__attribute__((aligned(n)))可以用于变量或者结构体,它告诉编译器将对象对齐到n字节边界。

默认情况下,编译器会按照最大基本类型的大小进行对齐,例如int型变量会按照4字节对齐。

例如,我们定义一个变量,并要求将其对齐到8字节边界:```int var __attribute__((aligned(8)));```在上面的例子中,变量var将被对齐到8字节边界。

3. __attribute__((noreturn))__attribute__((noreturn))用于告诉编译器一个函数不会返回。

这对于一些特殊的函数非常有用,如exit函数、abort函数等。

c语言结构体中的数组字节对齐

c语言结构体中的数组字节对齐

c语言结构体中的数组字节对齐C语言中的结构体是一种非常重要的数据类型,它可以将不同类型的数据组合在一起,形成一个新的数据类型。

在结构体中,我们可以定义不同类型的变量,包括整型、浮点型、字符型、指针等等。

除此之外,我们还可以在结构体中定义数组。

然而,在定义结构体中的数组时,我们需要注意到一个问题,那就是数组的字节对齐问题。

在C语言中,结构体中的变量是按照一定的字节对齐规则来排列的。

这个字节对齐规则是由编译器来决定的,不同的编译器可能会有不同的字节对齐规则。

在结构体中,每个变量都会占用一定的字节空间,而字节对齐规则则是为了保证结构体中的变量在内存中的存储位置是连续的,从而提高程序的执行效率。

在结构体中定义数组时,我们需要注意到数组的字节对齐问题。

在C语言中,数组的字节对齐规则是按照数组元素的大小来决定的。

例如,如果数组元素的大小是4个字节,那么数组的起始地址必须是4的倍数。

如果数组元素的大小是8个字节,那么数组的起始地址必须是8的倍数。

这样做的目的是为了保证数组元素在内存中的存储位置是连续的,从而提高程序的执行效率。

在结构体中定义数组时,我们需要注意到数组元素的大小和结构体的字节对齐规则。

如果数组元素的大小和结构体的字节对齐规则不一致,那么就会出现字节对齐的问题。

例如,如果结构体的字节对齐规则是按照4个字节对齐,而数组元素的大小是3个字节,那么就会出现字节对齐的问题。

在这种情况下,编译器会在数组元素之间插入一些填充字节,以保证数组元素在内存中的存储位置是连续的。

为了避免结构体中数组的字节对齐问题,我们可以采用一些方法来解决。

其中一种方法是使用#pragma pack指令来改变结构体的字节对齐规则。

例如,我们可以使用#pragma pack(1)指令来将结构体的字节对齐规则改为按照1个字节对齐。

这样做的缺点是会增加内存的使用量,从而降低程序的执行效率。

另一种方法是使用位域来定义结构体中的变量。

位域是一种特殊的数据类型,它可以将一个字节中的多个位分别用来表示不同的变量。

Arm结构体gcc内存边界对齐问题

Arm结构体gcc内存边界对齐问题

Arm结构体gcc内存边界对齐问题这段时间移植公司的linux i386程序到Arm linux平台,本以为是件工作量很小的事情,以为只要改几个驱动程序就OK了,没想到在应用程序这一块卡了很长时间。

其中最烦的事情就莫过于结构体内存边界对齐了。

搞了这么久,终于终结了一些小经验。

默认情况下,在32位cpu里,gcc对于结构体的对齐方式是按照四个字节来对齐的。

看以下结构体typedef struct pack{char a;int b;short c;}pack;对于Pack结构体,默认情况下在arm/386平台下(别的平台没试过)sizeof(pack)=12,求解过程如下:sizeof(char)=1;下一个int b,由于是四个字节,要求b的开始地址从32的整数倍开始,故需要在a后面填充3个没用的字节,记为dump(3),sizeof(b)=4,此时相当于结构体扩充为char a;char dump(3);int b;看short c,现在c的前面有8个字节,c是两个字节,c的开始地址是从16的整数开始,在b前面不需再加东西.此时对于结构体来说,sizeof(pack)=10,但是这不是最终结果,最后总的字节数也要能被4个字节整除,所以还需在short c后面再加dump(2);故总的字节数为12.当然以上说的只是简单的情况,下面谈谈Arm,x86在gcc里关于内存边界字节对齐的区别.对于同样的结构体,在386下#prama pack(1)后,sizeof(pack)=1 4 2=7而在arm下同样的操作sizeof(pack)=1 4 2 1=8,即虽然b根a之间不要填充但总的长度必须要是4的整数倍.在ARM 下要使结构体按指定字节对齐,可行的方法1.在makefile里加-fpack-struct 选项,这样的话对所有的结构按一字节对齐.不得不说,确实有那么些质量较差的程序可能需要你部分自然对齐,部分一字节对齐,此时2. typedef struct pack{}__attribute__((packed))可利用__attribute__属性当然最后的方式,还是自己去看ARM体系结构与gcc编译选项了。

FATFS一个小BUG搞了我2天才解决.特此发帖,希望大家不要重蹈我的覆辙.

FATFS一个小BUG搞了我2天才解决.特此发帖,希望大家不要重蹈我的覆辙.

FATFS一个小BUG搞了我2天才解决.特此发帖,希望大家不要重蹈我的覆辙.只要执行过红线,就进入hard_fault了...经验告诉我,这肯定是内存访问有问题.于是对比成功和失败两个版本的fs,wsect,fs->fatbase,fs->fsize 他们对应值都一样这样,哥迷茫了...于是使出浑身解数,疯狂替换反替换,结果还是一样...后来发现我的综合实验使用了-o1,等优化选项.于是设置为一模一样.此时终于可以f_mkdir了...但是作为普通实验,没必要开优化啊...所以还得找原因.没办法,最后用绝招了,从最简单的做起,把不相干的代码统统砍掉.最后在去掉malloc的时候,奇迹终于出现了...把如下代码://为exfuns申请内存//返回值:0,成功//1,失败u8 exfuns_init(void){fs[0]=(FATFS*)mymalloc(SRAMIN,sizeof(FATFS)); //为磁盘0工作区申请内存fs[1]=(FATFS*)mymalloc(SRAMIN,sizeof(FATFS)); //为磁盘1工作区申请内存file=(FIL*)mymalloc(SRAMIN,sizeof(FIL)); //为file申请内存ftemp=(FIL*)mymalloc(SRAMIN,sizeof(FIL)); //为ftemp申请内存fatbuf=(u8*)mymalloc(SRAMIN,512); //为fatbuf申请内存if(fs[0]&&fs[1]&&file&&ftemp&&fatbuf)return 0; //申请有一个失败,即失败.else return 1;}不用malloc,而直接用全局数组来实现,就可以正常工作.然后发现FATFS本来只有562字节,但是sizeof之后,却是564字节,反复数了N遍,确认FATFS只有562字节,这多了的2个字节,肯定就是FATFS结构体数据对其的问题了,于是赶紧在FATFS结构体前面加上__paked关键字.如下:__packed typedef struct {BYTE fs_type; /* FAT sub-type (0:Not mounted) */BYTE drv; /* Physical drive number */BYTE csize; /* Sectors per cluster (1,2,4...128) */BYTE n_fats; /* Number of FAT copies (1,2) */BYTE wflag; /* win[] dirty flag (1:must be written back) */BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */ WORD id; /* File system mount ID */WORD n_rootdir; /* Number of root directory entries (FAT12/16) */#if _MAX_SS != 512WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */#endif#if _FS_REENTRANT_SYNC_t sobj; /* Identifier of sync object */#endif#if !_FS_READONLYDWORD last_clust; /* Last allocated cluster */DWORD free_clust; /* Number of free clusters */DWORD fsi_sector; /* fsinfo sector (FAT32) */#endif#if _FS_RPATHDWORD cdir; /* Current directory start cluster (0:root) */#endifDWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */DWORD fsize; /* Sectors per FAT */DWORD fatbase; /* FAT start sector */DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */DWORD database; /* Data start sector */DWORD winsect; /* Current sector appearing in the win[] */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */} FATFS;之后再用sizeof,得到FATFS大小是562字节了...然后再次加入malloc,代码也可以正常工作了.至此,该问题终于解决了.究其原因,就是FATFS结构体的字节对齐问题.所以建议大家在自己建立结构体的时候,最好加上__packed关键字,免得再出现这种郁闷的情况.浪费2天...不过也有所收获.。

结构体对齐规则

结构体对齐规则

结构体对齐规则1、什么是内存对齐?我们都知道,定义的变量(元素)是要按照顺序一个一个放到内存中去的,它们也不一定就是紧密排列的,是要按照一定的规则就行排放的,这就是内存对齐。

对结构体来说,元素的存储从首地址开始,第一个元素的地址和整个结构体的首地址相同,其他的每个元素放置到内存中时,它都会认为内存是按照元素自己的大小来划分空间的,所以元素放置在内存中的位置一定会在元素自己宽度(字节数)的整数倍上开始,这就是所谓的结构体内存对齐问题。

特别有意思的是,C语言同意使用者自行确定内存对齐的设置,通过伪指令#pragma pack (n) 可以重新设定内存对齐的字节数。

这个后面会讲到!2、为什么要有内存对齐?这真是一个好问题!从网上了解到的几个原因:(1)考虑平台的原因。

实际的硬件平台跑代码是有所区别的,一些硬件平台可以对任意地址上的任意数据进行访问,而有一些硬件平台就不行,就是有限制,所以内存对齐是一种解决办法。

(2)考虑性能的原因。

CPU访问内存时,如果内存不对齐的话,为了访问到数据的话就需要几次访问,而对齐的内存只需要访问一次即可,提高了CPU访问内存的速度。

3、结构体的内存对齐规则是什么?每当有用到结构体的时候,总会考虑这个结构体实际应该要占用多少的内存,是否还有优化的空间。

特别是在面试时,结构体的内存对齐问题是很多面试会考到,也会经常被提及问起,属于高频考点了!话不多说,直接奉上结构体的内存对齐的判别方法,方便大家快速算出结构体所占的内存大小。

这里先规定一下:内存对齐值称为内存对齐有效值,这个值可以是1、2、4、8、16,所以先规定一下。

规则:规则1,结构体第一个成员一定是放在结构体内存地址里面的第1位。

规则2,成员对齐规则:除了第一个成员,之后的每个数据成员的对齐要按照成员自身的长度和内存对齐有效值进行比较,按两者中最小的那个进行对齐,即偏移的倍数。

规则3,结构体整体对齐规则:数据成员完成对齐之后,对整个结构体的大小进行对齐。

c语言字节对齐规则

c语言字节对齐规则

c语言字节对齐规则
C语言字节对齐规则
字节对齐(Byte Alignment)是指内存地址和数据类型中字节的排列位置,由于内存地址以字节为单位进行分配,数据类型却有特定的字节内存空间,所以为了让数据类型跟内存地址对齐,就必须让数据类型的内存空间按照一定的对齐规则进行排列,这样才能让数据类型最小的内存空间能得到最优的分配。

C语言的字节对齐规则
1、C语言中,结构体的属性是以字节为单位进行分配的。

2、对于大小为1字节的变量,不管在结构体的哪个位置,都不会进行字节对齐,一个变量一个字节就是一个字节,不会增加其他字节的占用。

3、对于大小为2字节的变量,要求其在结构体的位置为偶数,将会对其右边多出一个字节的占用,但是不会多出一个字节的内存,只是在内存的右边多出一个字节的位置而已。

4、对于大小为4字节的变量,要求其在结构体的位置为4的倍数,也会对其右边多出三个字节的占用,但是不会多出三个字节的内存,只是在内存的右边多出三个字节的位置而已。

5、对于大小为8字节的变量,要求其在结构体的位置为8的倍数,也会对其右边多出七个字节的占用,但是不会多出七个字节的内存,只是在内存的右边多出七个字节的位置而已。

6、C中的枚举常量和指针类型都会进行字节对齐,枚举常量和
指针类型都会被当做int类型来对齐,即按照4个字节的方式对齐。

7、C语言中,数组也会进行字节对齐,但是这里需要根据该数组的元素的大小来决定字节对齐的规则,如果数组的元素大小是1字节,则不进行字节对齐;如果是2字节,则按照2字节对齐规则进行字节对齐;如果数组的元素大小是4字节,则按照4字节的对齐规则进行字节对齐;如果大于4字节,则按照8字节的对齐规则进行字节对齐。

keilmdk+stm32的ac5和ac6两个编译器下的字节对齐操作方法

keilmdk+stm32的ac5和ac6两个编译器下的字节对齐操作方法

keilmdk+stm32的ac5和ac6两个编译器下的字节对齐操作⽅法最近在使⽤ac6.9的编译器,编译速度是真的很快,使⽤stm32的hal库编译速度也⽐ac5的编译器快很多。

本⽂试验stm32中字节对齐的代码测试,主要是结构体,因为结构体中实际项⽬中⽤到最多,同时在仿真环境中打印出来。

ac5的测试结果:#ifdef CC_ARM_AC5//该⽅式只是使⽤ac5编译器,结构体不对齐的⽅式1,结构体的长度,就是各个变量长度的和__packed typedef struct _li_st{uint8_t a; //1个uint16_t b; //2个uint32_t c; //4个uint64_t d; //8个}li_st;//ac5编译器的结构体不对齐的⽅式2,结构体的长度,就是各个变量长度的和typedef struct _li_st_2{uint8_t a; //1个uint16_t b; //2个uint32_t c; //4个uint64_t d; //8个}__attribute__((__packed__)) li_st_2;//)到4字节,同样可指定对齐到8字节。

typedef struct student_4B{char name[7]; //7+1=8uint32_t id; //4char subject[5]; //5+3=8} __attribute__((aligned(4))) li_st_4B;#pragma pack (1) /*指定按1字节对齐⽅式3*/typedef struct _li_st_1B{uint8_t a; //1个uint16_t b; //2个uint32_t c; //4个uint64_t d; //8个}li_st_1B;#pragma pack () /*取消指定对齐,恢复缺省对齐*/#pragma pack (2) /*指定按2字节对齐*/typedef struct _li_st_2B{char b;int a;short c;}li_st_2B;#pragma pack () /*取消指定对齐,恢复缺省对齐*/测试结果如下:ac6的测试结果:#elif (CC_ARM_AC6)//ac6 ac5通⽤,的结构体不对齐⽅式,结构体的长度,就是各个变量长度的和typedef struct _li_st_ac6{uint8_t a; //1个uint16_t b; //2个uint32_t c; //4个uint64_t d; //8个}__attribute__((packed)) li_st_ac6 ;//ac6 ac5通⽤,的结构体不对齐⽅式2,结构体的长度,就是各个变量长度的和#pragma pack (1) /*指定按1字节对齐*/typedef struct _li_st_ac6_1B{uint8_t a; //1个uint16_t b; //2个uint32_t c; //4个uint64_t d; //8个}li_st_ac6_1B;#pragma pack () /*取消指定对齐,恢复缺省对齐*///ac6 ac5通⽤,下⾯的定义和8字节⼀样的⼤⼩,主要看内存分布#pragma pack (4) /*指定按4字节对齐*/typedef struct _li_st_ac6_4B{uint8_t a; //1个 + 1uint16_t b; //2个uint32_t c; //4个uint64_t d; //8个}li_st_ac6_4B;#pragma pack () /*取消指定对齐,恢复缺省对齐*/。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

结构体字节对齐typedef __packed struct
之前一直很少用结构体,但最近随着变量的直线上升,不得不采用结构体。

对于struct,理解并不是很深入,最近一段时间的应用,发现struct的强大。

作为一种数据集合,struct常用在数据结构中。

而struct的字节对齐方式对于嵌入式底层的程序员来讲是必须掌
握的。

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的
排放,这就是对齐。

对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。

一些平台对某些特定类型的数据只能从某些特定地址开始存取。

比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其
平台要求对数据存放进行对齐,会在存取效率上带来损失。

比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。

显然在读取效率上下降很多。

下面看一个例子(32bit,x86环境,VC++6.0编译器):
struct A
{
int a;
char b;
short c;
};
struct B
{
char b;
int a;
short c;
};我们知道在VC++6.0中,以上几种数据类型的长度
如下:
char: 1;
int: 4;
short:2;
以上两个结构体的大小如下:
sizeof(strcut A)值为8
sizeof(struct B)值是12;
结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个,B 也一样;按理说A,B大小应该都是7字节。

之所以出现上面的结果是因为编译器要对数据成员在空间上进行对齐。

以上是按默认方式对齐。

如果指定对齐方式:
#pragma pack (2) /*指定按2字节对齐*/
struct C
{
char b;
int a;
short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐
*/sizeof(struct C)值是8。

修改对齐值为1:
#pragma pack (1) /*指定按1字节对齐*/
struct D
{
char b;
int a;
short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/ sizeof(struct D)值为7。

ARM下的对齐处理,可以使
用 __packed
typedef struct
{
char x;
int y;
}struct1;
typedef __packed struct
{
char x;
int y;
}struct2;在32位的ARM SDT编译器中
sizeof(struct1)值为8
sizeof(struct2)值为5;
__packed是进行一字节对齐。

使用_packed一般会以降低运行性能为代价,由于大多数cpu处理数据在合适的字节边界数的情况下会更有效,packed的使用会
破坏这种自然的边界数。

相关文档
最新文档