下面是正在考虑的代码:
#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字节(大小对齐的地址中。我期望在执行此命令期间执行以下操作:
- 指向缓冲区的指针,即
char*
,增加pos
的值(0,9,18,27(,然后增加4。得到的指针是指向字符数组索引[pos + 4]
的char*
- 括号中的
char*
指针被转换为int*
,导致指针寻址基位置(buffer + pos + 4)
和整数数组索引[0]
处的4字节大小的整数 - 所得到的CCD_ 9位置以字节78 56 34 12的顺序存储(小端序系统(
相反,我看到括号中的指针与int
(4字节(的大小对齐,但使用常量的直接寻址(请参阅第二段代码(可以正常工作。
- 目标CPU为i.MX287(ARM9(
- 目标操作系统是OpenWrt
Linux [...] 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));