gpt4 book ai didi

c++ - 为什么调用 memcpy 到 bool 值后 memcpy 到 int 不起作用

转载 作者:搜寻专家 更新时间:2023-10-31 02:02:49 26 4
gpt4 key购买 nike

我在玩 memcpy 时偶然发现了一个奇怪的结果,在 bool memcpy 之后对同一内存指针调用的 memcpy 给出了意想不到的结果。

我创建了一个简单的测试结构,其中包含一堆不同类型的变量。我将结构转换为 unsigned char 指针,然后使用 memcpy 将数据从该指针复制到单独的变量中。我试着绕过 memcpy 的偏移量并将 int memcpy 移到 bool 之前(更改了测试结构的布局,以便 int 也位于 bool 之前)。令人惊讶的是,转移解决了问题。

// Simple struct containing 3 floats
struct vector
{
float x;
float y;
float z;
};

// My test struct
struct test2
{
float a;
vector b;
bool c;
int d;
};

int main()
{
// I create my structure on the heap here and assign values
test2* test2ptr = new test2();
test2ptr->a = 50;
test2ptr->b.x = 100;
test2ptr->b.y = 101;
test2ptr->b.z = 102;
test2ptr->c = true;
test2ptr->d = 5;

// Then turn the struct into an array of single bytes
unsigned char* data = (unsigned char*)test2ptr;
// Variable for keeping track of the offset
unsigned int offset = 0;

// Variables that I want the memory copied into they
float a;
vector b;
bool c;
int d;

// I copy the memory here in the same order as it is defined in the struct
std::memcpy(&a, data, sizeof(float));
// Add the copied data size in bytes to the offset
offset += sizeof(float);

std::memcpy(&b, data + offset, sizeof(vector));
offset += sizeof(vector);

std::memcpy(&c, data + offset, sizeof(bool));
offset += sizeof(bool);

// It all works until here the results are the same as the ones I assigned
// however the int value becomes 83886080 instead of 5
// moving this above the bool memcpy (and moving the variable in the struct too) fixes the problem
std::memcpy(&d, data + offset, sizeof(int));
offset += sizeof(int);

return 0;
}

所以我预计 d 的值为 5,但它变成了 83886080,我认为这只是随机未初始化的内存。

最佳答案

您忽略了结构中数据的填充。

看看下面的简化示例:

struct X
{
bool b;
int i;
};

int main()
{
X x;
std::cout << "Address of b " << (void*)(&x.b) << std::endl;
std::cout << "Address of i " << (void*)(&x.i) << std::endl;
}

这在我的电脑上的结果是:

Address of b 0x7ffce023f548

Address of i 0x7ffce023f54c

如您所见,结构中的 bool 值在这里占用 4 个字节,即使它在其内容中使用的更少。编译器必须向结构添加填充字节,以使 cpu 可以直接访问数据。如果您将数据按照代码中的写入方式进行线性排列,则编译器必须针对所有访问生成汇编指令,以便稍后对齐数据,这会大大降低您的程序速度。

您可以通过添加 pragma pack 或与您的编译器类似的东西来强制编译器这样做。所有的 pragma 都是特定于编译器的!

对于您的程序,如果 memcpy 的数据不是您要访问的元素之前的数据元素的大小,则必须使用地址,因为这会忽略填充字节。

如果我在我的程序之前添加一个pragma pack(1),输出是:

Address of b 0x7ffd16c79cfb

Address of i 0x7ffd16c79cfc

如您所见,bool 和 int 之间不再有填充字节。但是后面访问 i 的代码会很大很慢!所以完全避免使用 #pragma pack!

关于c++ - 为什么调用 memcpy 到 bool 值后 memcpy 到 int 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56584353/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com