b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

C语言中的结构对齐问题

电脑杂谈  发布时间:2020-07-08 21:20:13  来源:网络整理

c#结构体内声明数组_结构体数组_数组位图结构链表队列堆栈 c

对齐方式的使用

1 .__ align(num)

这用于修改最高级别对象的字节边界. 在组装中使用LDRD或STRD时

此命令__align(8)将用于限制修改. 为确保数据对象相应对齐.

修改对象的命令最大为8个字节,对于2个字节的对象允许4个字节

对齐,但是不能对齐4个字节对象的2个字节.

__ align是存储类的修改. 它仅修改最高级别的类型对象,而不能用于结构或功能对象.

2 .__ packed

__ packed用于一字节对齐

1. 无法对齐打包的对象

2. 对所有对象具有读写访问权限的非读写访问权限

3. 浮点数和包含浮点数和未使用的__packed对象的结构将不按字节对齐

4 .__ packed对局部整形变量没有影响

5. 强制从未包装的对象到包装的对象的转换是不确定的,并且可以合法设置塑料指针

意味深长.

__ packed int * p; // __ packed int没有意义

6. 对齐或未对齐的读写访问权限引起的问题

__打包的结构STRUCT_TEST

{

字符a;

int b;

字符c;

}; //此时定义以下结构,b的起始地址必须未对齐

///访问堆栈中的b可能存在问题,因为必须对齐堆栈中的数据[从CL]

///将以下变量定义为不在堆栈上的全局静态变量

静态字符* p;

静态结构STRUCT_TEST a;

void Main()

{

__ packed int * q; //此时,它被定义为__packed,以修改q指向未对齐数据的数据地址下方的访问.

p =(字符*)&a;

q =(int *)(p + 1);

* q = 0x87654321;

/ *

明确分配的组装指令

ldr r5,0x20001590; =#0x12345678

[0xe1a00005] mov r0,r5

[0xeb0000b0] bl __rt_uwrite4 //调用操作函数在此处写入4个字节

[0xe5c10000] strb r0,[r1,#0] //该函数执行strb操作4次,然后返回以确保对数据的正确访问

[0xe1a02420] mov r2,r0,lsr#8

[0xe5c12001] strb r2,[r1,#1]

[0xe1a02820] mov r2,r0,lsr#16

[0xe5c12002] strb r2,[r1,#2]

[0xe1a02c20] mov r2,r0,lsr#24

[0xe5c12003] strb r2,[r1,#3]

[0xe1a0f00e] mov pc,r14

* /

/ *

如果未使用__packed修改q,则汇编的指令将直接导致无法访问奇数地址

[0xe59f2018] ldr r2,0x20001594; =#0x87654321

[0xe5812000] str r2,[r1,#0]

* /

//这可以清楚地看到未对齐的访问如何产生错误

//以及如何消除不对齐访问引起的问题

//您还可以看到未对齐访问和对齐访问之间的指令差异会导致效率问题

}

sizeof判断结构的大小

数组位图结构链表队列堆栈 c_结构体数组_c#结构体内声明数组

typedef结构

{

int a;

字符b;

} A_t;

typedef结构

{

int a;

字符b;

字符c;

} B_t;

typedef结构

{

字符a;

int b;

字符c;

} C_t;

void main()

{

char * a = 0;

cout

为什么会这样?

2. 语法:

sizeof具有三种语法形式,如下:

1)sizeof(object); // sizeof(object);

2)sizeof(type_name); // sizeof(type);

3)sizeof对象; // sizeof对象;

5. sizeof指针变量

因为它用于存储地址,所以它当然等于计算机内部地址总线的宽度. 因此,在一台32位计算机上,

指针变量的返回值必须为4(以字节为单位),可以预见在将来的64位系统中

中的指针变量的大小结果

是8.

char * pc =“ abc”;

int * pi;

string * ps;

char ** ppc =&pc;

void(* pf)(); //函数指针

sizeof(pc); //结果为4

sizeof(pi); //结果为4

sizeof(ps); //结果为4

sizeof(ppc); //结果为4

sizeof(pf); //结果是4

指针变量的sizeof值与指针所指向的对象无关,正是因为所有指针变量都占用了内存

大小相等,因此MFC消息处理功能可以使用两个参数WPARAM,LPARAM传递各种复杂的消息节点

结构(使用指向结构的指针).

6. 数组的大小

数组的sizeof值等于数组占用的内存字节数,例如:

char a1 [] =“ abc”;

int a2 [3];

sizeof(a1); //结果为4,字符串末尾有一个NULL终止符

sizeof(a2); //结果为3 * 4 = 12(取决于int)

一些朋友在开始时使用sizeof作为数组元素的数量. 现在结构体数组,您应该知道这是错误的,然后

我应该如何找到数组元素的数量?很简单,通常有以下两种书写方式:

int c1 = sizeof(a1)/ sizeof(char); //总长度/单个元素的长度

int c2 = sizeof(a1)/ sizeof(a1 [0]); //总长度/第一个元素的长度

在这里写问,下面的c3和的值应该是什么?

void foo3(char a3 [3])

数组位图结构链表队列堆栈 c_c#结构体内声明数组_结构体数组

{

int c3 = sizeof(a3); // c3 ==

}

void foo4(char a4 [])

{

int = sizeof(a4); // ==

}

也许当您尝试回答的值时,您已经意识到c3是错误的,是的,c3!= 3. 这里的功能参数a3不再存在

等效于char * a3的数组类型而不是指针,为什么?如果您仔细考虑一下,我们就会打电话

使用函数foo1时,程序会在堆栈上分配大小为3的数组吗?将不会!数组被“通过地址传递”,调用者

您只需要传递实际参数的地址,因此a3自然是指针类型(char *),而c3的值为4.

7. 结构的大小

这是初学者最常问的问题,因此有必要花更多的时间在写作上. 首先让我们看一下结构:

结构S1

{

字符c;

int i;

};

sizeof(s1)多少钱?聪明,您开始思考,char占用1个字节,int占用4个字节,然后加起来

应该是5. 是吗?您在机器上尝试过吗?也许您是对的,但很可能您是错的! V

在C6中默认设置获得的结果是8.

为什么?为什么我总是受伤的人?

请不要沮丧,让我们考虑一下sizeof的定义-sizeof的结果等于对象或类型

内存字节数,好的,让我们看一下S1的内存分配:

S1 s1 = {a,0xFFFFFFFF};

定义上述变量后,添加一个断点,运行程序结构体数组,并观察s1所在的内存. 你发现了什么?

以VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:

0012FF78: 61 CC CC CC FF FF FF FF

您找到了什么?为什么中间有3个字节的CC?看看MSDN上的说明:

应用于结构类型或变量时,sizeof返回实际大小,

其中可能包括为对齐而插入的填充字节.

原来,这是传奇的字节对齐!一个重要的话题出现了.

为什么需要字节对齐?计算机组成原理告诉我们,它将有助于加快计算机访问速度,否则

这需要更多的指令周期. 因此,编译器会默认处理结构(实际上,其他位置的数据会发生变化

金额也是如此),因此宽度为2(短等)的基本数据类型位于可被2整除的地址处,因此宽度

基本数据类型4(整数等)位于可被4整除的地址上,依此类推. 这样,两个数字的中间

您可能需要添加填充字节,因此整个结构的sizeof值会增加.

让我们交换char和int在S1中的位置:

结构S2

{

int i;

字符c;

};

看看sizeof(S2)的结果,它怎么还是8?再次查看内存,原始成员c后面仍然有三个填充词.

部分

,为什么呢?不用担心,让我们总结以下规则.

字节对齐的详细信息与编译器的实现有关,但是一般而言,满足三个条件:

1)结构变量的首地址可以除以其最宽的基本类型成员的大小;

2)结构中每个成员相对于结构的第一个地址的偏移量是该成员大小(如果有)的整数倍

要求编译器在成员之间添加内部字节;

3)结构的总大小是该结构最宽的基本类型成员的大小的整数倍,如有必要,编译器将是最后一个

之后

成员,添加了尾随填充.

对于上述准则,有几点需要解释:

1)我并不是说结构成员的地址是其大小的整数倍. 偏移量如何?因为第一个

存在一点,因此我们只能考虑成员的偏移量,这使考虑起来很简单. 考虑一下原因.

结构的成员相对于结构的第一个地址的偏移量可以通过宏offsetof()获得,该宏也位于

数组位图结构链表队列堆栈 c_结构体数组_c#结构体内声明数组

在stddef.h中定义,如下所示:

#define offsetof(s,m)(size_t)&((((s *)0)-> m)

例如,如果要在S2中获取c的偏移量,则方法为

size_t pos = offsetof(S2,c); // pos等于4

2)基本类型是指前面提到的内置数据类型,例如char,short,int,float和double,

此处提到的“数据宽度”是指其sizeof. 由于结构的成员可以是复合类型,因此

就像另一种结构,因此在寻找最宽的基本类型成员时,应包括复合类型成员的子成员,

代替整体上对待复合成员. 但是,在确定复合类型的成员的偏移位置时,它是复合类型

整体查看.

这里描述有点草率,想起来有点草率,让我们看一下示例(具体值为VC

6是一个示例,以后将不作介绍):

结构S3

{

char c1;

S1 s;

字符c2

};

S1的最简单成员的类型为int,考虑到最简单的成员,S3会“分解” S1,因此

S3的最简单类型是int,因此需要将S3定义的变量的存储空间的第一个地址除以4,然后将整个数除以

sizeof(S3)的值也应被4整除.

c1的偏移量为0,那么s的偏移量呢?此时s是一个整体,作为结构变量,它也满足前三个条件

,因此它的大小是8,偏移量是4. c1和s之间需要3个填充字节,但c2和s之间不需要,

所以c2的偏移量是12,c2的大小是13,而13不能被4整除,因此末端必须用3个填充填充

收费字节. 最后,sizeof(S3)的值为16.

通过上面的描述,我们可以获得一个公式:

结构的大小等于最后一个成员的偏移量加上其大小加上末尾的填充字节数,即:

sizeof(结构)= offsetof(最后一项)+ sizeof(最后一项)+ sizeof(尾迹

填充)

这时,朋友应该对结构的大小有了新的了解,但不要太高兴,有一个

尚未提及影响sizeof的重要参数,即编译器的pack指令. 用于调整结构的对齐方式

不同编译器的方式,名称和用法略有不同. 它是通过VC6中的#pragma pack实现的,也可以直接对其进行修改

/ Zp编译开关. #pragma pack(n)的基本用法是: #pragma pack(n),n是字节对齐号及其值

1、2、4、8、16,默认值为8,如果该值小于结构成员的sizeof值,则该成员的偏移量

数量应基于此值,即结构成员的偏移量应为两者中的最小值,公式如下:

offsetof(item)= min(n,sizeof(item))

再次查看示例:

#pragma pack(push)//将当前包设置保存在堆栈中

#pragma pack(2)//必须在结构定义之前使用

结构S1

{

字符c;

int i;

};

结构S3

{

char c1;

S1 s;

字符c2

};

#pragma pack(pop)//恢复以前的包设置

计算sizeof(S1)时,min(2,sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)等于

6,可被2整除,因此整个S1的大小为6.

类似地,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能为

除以2会添加一个填充字节,因此sizeof(S3)等于10.

现在,朋友可以轻松呼吸了,

还需要注意的是,“空结构”(没有数据成员)的大小不是0,而是1. 想象一下“不计算”

“空格”变量的地址如何区分两个不同的“空结构”变量?因此,“

数组位图结构链表队列堆栈 c_结构体数组_c#结构体内声明数组

还必须存储空结构变量,以便编译器只能为占位符分配一个字节的空间.

如下:

struct S5 {};

sizeof(S5); //结果为1

8. 包含位域结构的sizeof

如前所述,不能将位字段的成员单独视为sizeof值. 我们在这里讨论的是包含位字段的结构

的大小

仅出于其特殊性列出.

C99规定可以将int,unsigned int和bool用作位字段类型,但是几乎所有编译器都将其扩展为允许

允许其他类型的存在.

使用位字段的主要目的是压缩存储,一般规则是:

1)如果相邻位字段的类型相同,并且它们的位宽之和小于该类型的sizeof大小,则以下字段将为

在上一个字段旁边存储,直到无法容纳为止;

2)如果相邻位字段的类型相同,但是它们的位宽之和大于该类型的大小,则以下字段将为

从新的存储单元开始,其偏移量是其类型大小的整数倍;

3)如果相邻位字段字段的类型不同,则每个编译器的具体实现是不同的,并且VC6不采用压缩方法

Dev-C ++使用压缩;

4)如果非位字段散布在位字段之间,将不执行压缩;

5)整个结构的总大小是最宽的基本类型成员的大小的整数倍.

让我们看一个例子.

示例1:

结构BF1

{

char f1: 3;

char f2: 4;

char f3: 5;

};

内存布局为:

| _f1__ | __f2__ | ______ f3 ___ | ____ |

| _ | _ | _ | _ | _ | _ | ____________________ |

0 3 7 8 1316

位字段类型为char,第一个字节只能容纳f1和f2,因此f2被压缩为第一个字节,而f3只能容纳

从下一个字节开始. 因此,sizeof(BF1)的结果为2.

示例2:

结构BF2

{

char f1: 3;

短f2: 4;

char f3: 5;

};

由于相邻位字段的类型不同,在VC6中它的sizeof为6,在Dev-C ++中它的大小为2.

示例3:

结构BF3

{

char f1: 3;

char f2;

char f3: 5;

};

非位字段散布在其中,不会进行压缩,并且在VC6和Dev-C ++中获得的大小为3.

9. 财团规模

该结构在内存组织中是顺序的,并且联合是重叠的. 每个成员共享一段记忆,所以整个联合会

组合的sizeof是每个成员的最大大小. 结构的成员也可以是复合类型,在这里,

复合类型成员被视为一个整体.

因此,在下面的示例中,U的sizeof值等于sizeof(s).

联盟U

{

int i;

字符c;

S1 s;

};


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-273347-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...