c-为什么最后一个指针要和int的大小对齐



下面是正在考虑的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
char buffer[512];
int pos;
int posf;
int i;
struct timeval *tv;
int main(int argc, char **argv)
{
pos = 0;
for (i = 0; i < 512; i++) buffer[i] = 0;
for (i = 0; i < 4; i++)
{
printf("pos = %dn", pos);
*(int *)(buffer + pos + 4) = 0x12345678;
pos += 9;
}
for (i = 0; i < 9 * 4; i++)
{
printf(" %02X", (int)(unsigned char)*(buffer + i));
if ((i % 9) == 8) printf("n");
}
printf("n");
// ---  
pos = 0;
for (i = 0; i < 512; i++) buffer[i] = 0;
*(int *)(buffer + 4) = 0x12345678;
*(int *)(buffer + 9 + 4) = 0x12345678;
*(int *)(buffer + 18 + 4) = 0x12345678;
*(int *)(buffer + 27 + 4) = 0x12345678;
for (i = 0; i < 9 * 4; i++)
{
printf(" %02X", (int)(unsigned char)*(buffer + i));
if ((i % 9) == 8) printf("n");
}
printf("n");
return 0;
}

并且代码的输出是

pos = 0
pos = 9
pos = 18
pos = 27
00 00 00 00 78 56 34 12 00
00 00 00 78 56 34 12 00 00
00 00 78 56 34 12 00 00 00
00 78 56 34 12 00 00 00 00
00 00 00 00 78 56 34 12 00
00 00 00 00 78 56 34 12 00
00 00 00 00 78 56 34 12 00
00 00 00 00 78 56 34 12 00

我不明白为什么

*(int *)(buffer + pos + 4) = 0x12345678;

正在放入与int(4字节(大小对齐的地址中。我期望在执行此命令期间执行以下操作:

  1. 指向缓冲区的指针,即char*,增加pos的值(0,9,18,27(,然后增加4。得到的指针是指向字符数组索引[pos + 4]char*
  2. 括号中的char*指针被转换为int*,导致指针寻址位置(buffer + pos + 4)和整数数组索引[0]处的4字节大小的整数
  3. 所得到的CCD_ 9位置以字节78 56 34 12的顺序存储(小端序系统(

相反,我看到括号中的指针与int(4字节(的大小对齐,但使用常量的直接寻址(请参阅第二段代码(可以正常工作。

  • 目标CPU为i.MX287(ARM9(
  • 目标操作系统是OpenWrtLinux [...] 3.18.29 #431 Fri Feb 11 15:57:31 2022 armv5tejl GNU/Linux
  • Linux [...] 4.15.0-142-generic #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux上编译,安装在虚拟机中
  • GCC编译器版本gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
  • 我把编译作为整个系统镜像编译的一部分,标志是CFLAGS = -Os -Wall -Wmissing-declarations -g3

更新:感谢Andrew Henle,我现在替换

*(int*)(buffer + pos + 4) = 0x12345678;

带有

buffer[pos + 4] = value & 0xff;
buffer[pos + 5] = (value >> 8) & 0xff;
buffer[pos + 6] = (value >> 16) & 0xff;
buffer[pos + 7] = (value >> 24) & 0xff;

我不敢相信我必须在32位微处理器系统上做这件事,无论它有什么架构,而且GCC不能正确地将int分割成字节或部分int字,并对这些部分执行RMW。

括号中的char*指针正在转换为int*,导致指针寻址基位置(buffer + pos + 4(处4字节大小的整数和整数数组索引[0]

当不满足int *的对齐要求时,这会导致未定义的行为(UB(。

而是使用memcpy()进行复制。一个好的编译器会发出有效的优化代码。

// *(int*)(buffer + pos + 4) = 0x12345678;
memcpy(buffer + pos + 4, &(int){0x12345678}, sizeof (int));

最新更新