我的代码具有如下定义的结构类型:
typedef struct
{
Structure_2 a[4];
UCHAR b;
UCHAR c;
}Structure_1;
其中结构2的定义如下:
typedef struct
{
ULONG x;
USHORT y;
UCHAR z;
}Structure_2;
代码中还有两个函数。第一个(名为setter)声明“structure_1”类型的结构,并用数据填充它:
void setter (void)
{
Structure_1 data_to_send ;
data_to_send.a[0].x = 0x12345678;
data_to_send.a[0].y = 0x1234;
data_to_send.a[0].z = 0x12;
data_to_send.a[1].x = 0x12345678;
data_to_send.a[1].y = 0x1234;
data_to_send.a[1].z = 0x12;
data_to_send.a[2].x = 0x12345678;
data_to_send.a[2].y = 0x1234;
data_to_send.a[2].z = 0x12;
data_to_send.a[3].x = 0x12345678;
data_to_send.a[3].y = 0xAABB;
data_to_send.a[3].z = 0x12;
data_to_send.b =0;
data_to_send.c = 0;
getter(&data_to_send);
}
编译器将数据保存到内存中,如下所示:
第二个叫盖特:
void getter (Structure_1 * ptr_to_data)
{
UCHAR R_1 = ptr_to_data -> b;
UCHAR R_2 = ptr_to_data -> c;
/* The remaining bytes are received */
}
我希望Rç1的值是“00”,Rç2的值是“00”。
但编译器会将以下两行翻译成这样:
/* Get the data at the address ptr_to_data -> b,
which equals the start address of structure + 28 which contains the
value “AA”, and hence R_1 will have “AA” */
UCHAR R_1 = ptr_to_data -> b;
/* Get the data at the address ptr_to_data -> c,
which equals the start *address of structure + 29 which contains the
value “BB”, and hence R_2 will *have “BB” */
UCHAR R_2 = ptr_to_data -> c;
编译器在堆栈中保存结构时添加填充字节,但是当它开始读取它时,它会忘记它做了什么(并在读取中包含填充字节)。
如何通知编译器在读取结构元素时跳过填充字节?
我不想一个解决这个问题的办法,我很想知道为什么编译器会这样做?
我的编译器是GreenHills,目标是32位
最佳答案
如何通知编译器在读取结构元素时跳过填充字节?
简而言之:你不能。
编译器不会忽略结构中包含的内容。但是,您可以控制它如何处理结构中的内容。
我很想知道为什么编译器会这样做?
简而言之:数据对齐。
需要考虑两个问题:数据对齐边界和数据结构填充。你可以控制每一个:
数据对齐是编译器看到它所看到的东西的原因。数据对齐意味着将数据放在一个等于单词大小(对于32位环境为4字节)的某些倍数的内存地址,即使不使用显式填充,也会存储数据,以便观察这些边界,并且结构的大小将指示使用的总字节空间中的填充。
结构填充-将无意义的字节放入结构中,以帮助将大小调整为单词大小的倍数。你的示例代码中有这个。
您可以使用pragma macros使编译器以某种方式预处理(编译前解析)结构的打包:example#pragma pack(n)只是设置新的对齐方式。或者,#pragma pack()将对齐方式设置为编译开始时有效的对齐方式。
Example:
#pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */
struct MyPackedData
{
char Data1;
long Data2;
char Data3;
};
#pragma pack(pop) /* restore original alignment from stack */
注:
包(n)的n的单位是字节。n的值是特定于编译器的,例如MSVC的值通常是1、2、4、8和16。
问题:如果使用prama pack宏,它们在getter()/setter()函数之间是否使用一致的pack值?(归功于@alain)
但是,这不会导致编译器忽略结构的内容,只会以不同的方式处理它。
有关观察结果的根本原因的更多信息,请参见信息here和here。
关于c - 编译器在读取结构时会考虑其填充字节,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31840261/