1、问题代码
#include <QCoreApplication>
#pragma pack(push, 1)
typedef struct
{
int a; // 4字节
float b; // 4字节
char c; // 1字节
int *d; // 8字节
}testStruct;
#pragma pack(pop)
#include <QByteArray>
#include <QDebug>
int main()
{
testStruct structA;
structA.a = 1;
structA.b = 2;
structA.c = 'a';
structA.d = new int[10];
for (int i = 0; i < 10; ++i) {
structA.d[i] = i;
}
QByteArray arr;
arr.resize(49);
memcpy(arr.data(), &structA, 9);
memcpy(arr.data() + 9, structA.d, 40);
testStruct *sb = reinterpret_cast<testStruct *>(arr.data());
sb->d = reinterpret_cast<int *>(arr.data() + 9);
for (int i = 0; i < 10; ++i) {
qDebug() << sb->d[i];
}
return 0;
}
输出结果
40642209
0
2
3
4
5
6
7
8
9
2、调试过程1
经过调试指针转换后,发现本来设置的1字节对其变成了4字节对齐
QBytearray的data()指针被转换后会按照4字节自动对齐填充,不知为何会这样
>
3、调试过程2
当我采用系统默认的8字节对齐后,又发现无法正确的对结构体内指针进行赋值
下面这行代码,按理来说指针赋值,sb->d应该指向arr.data() + 16的地址上
typedef struct
{
int a; // 4字节
float b; // 4字节
char c; // 8字节
int *d; // 8字节
}testStruct;
sb->d = reinterpret_cast<int *>(arr.data() + 16);;
但实际上出现了一个奇怪的现象,在arr.data() + 16 的内存起始地址上,莫名填充了8个字节,而这8个字节恰好就是自己的内存地址??????
其中00 00 00 00 00 f6 43 48 等于 16139080,输出的第一个值正好为自己的地址
由此得出,结构体指针的赋值会将值和地址一并一起赋值?匪夷所思
4、测试代码
测试一下,对于原始的char* c指针是否也有这样的情况
#include <QCoreApplication>
#pragma pack(push, 1)
typedef struct
{
int a;
float b;
char c;
int *d;
}testStruct;
#pragma pack(pop)
#include <QByteArray>
#include <QDebug>
int main()
{
testStruct structA;
structA.a = 1;
structA.b = 2;
structA.c = 'a';
structA.d = new int[10];
for (int i = 0; i < 10; ++i) {
structA.d[i] = i;
}
QByteArray arr;
arr.resize(49);
memcpy(arr.data(), &structA, 9);
memcpy(arr.data() + 9, structA.d, 40);
testStruct *sb = reinterpret_cast<testStruct*>(arr.data());
// 分配一片char数组,假设我们需要存储3个float
char *charBuffer = new char[10 * sizeof(int)];
// 假设填充一些数据
int exampleData[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(charBuffer, exampleData, 10 * sizeof(int));
sb->d = reinterpret_cast<int*>(charBuffer);
// (*sb).d = reinterpret_cast<int*>(arr.data() + 16);
for (int i = 0; i < 10; ++i) {
qDebug() << sb->d[i];
}
return 0;
}
输出正常,给我整得一头雾水
5、问题解析
最后思来想去,终于发现了问题所在
结构体指针sb->d和需要解析的数据块在同一块内存地址,地址空间重合了!!!
在给sb->d的值赋值时,其实就是修改sb->d所在内存空间的8个字节为新的地址0x12345678,但是这块地址又和自己的数据地址重合了,所以导致了数据地址的前8个字节被覆盖