这是如何运作的?将任何东西复制到一个字节数组(字符)

时间:2010-09-22 18:10:54

标签: c++ c memory

struct MyRect
{
    int x, y, cx, cy;
    char name[100];
};

int main()
{
    MyRect mr;
    mr.x = 100;
    mr.y = 150;
    mr.cx = 600;
    mr.cy = 50;
    strcpy(mr.name, "Rectangle1");

    MyRect* ptr;

    {
        unsigned char bytes[256];

        memcpy(bytes, &mr, 256);

        ptr = (MyRect*)bytes;
    }

    printf("X = %d\nY = %d\nCX = %d\nCY = %d\nNAME = %s\n", 
        ptr->x, ptr->y, ptr->cx, ptr->cy, ptr->name);

    return 0;
}

我只是在测试如何将一个struct /类放在一个字节数组中,并且在编译和工作时很惊讶,printf打印出我在mr变量中设置的所有值。

对“ptr”指向的内容有点困惑?它在某处为ptr分配了内存吗?

6 个答案:

答案 0 :(得分:9)

它纯粹的机会。

首先,您基本上是对结构进行逐字节复制,并使用memcpy将其放入堆栈分配的缓冲区中。但是,你不应该在实践中这样做。这次碰巧工作了,因为你的结构是POD(普通旧数据或C结构),但是如果你的结构是带有构造函数/复制构造函数的C ++对象,或者你有什么,得到了一个令人讨厌的惊喜。

其次,包含结构的堆栈分配缓冲区在你通过指针使用时超出了范围,所以你所做的只是undefined behavior。它只能通过纯粹的机会运行,并且不能保证在不同的计算机上或使用不同的编译器,甚至在一天的不同时间再次工作。

答案 1 :(得分:2)

好吧,你的程序会导致未定义的行为,所以你可能不会感到惊讶它恰好工作。或者,如果它不能正常工作或导致宇宙结束,那么就是这样。在包含bytes定义的块之后,ptr超出范围,并且可能或可能仍未指向有效内存。在你的情况下,它确实如此。但你不能依赖这种行为。

答案 2 :(得分:2)

unsigned char bytes[256]在堆栈上分配,即每次输入函数(在本例中为main)时,堆栈上为变量bytes保留256字节。通过转换ptr现在指向堆栈上的此区域并解释为类型MyRect。由于您首先将此类结构复制到堆栈区域,因此这一切都很好并且有效。但是一旦离开main,区域ptr指向的区域就消失了,因此您可能不会在该函数之外存储指向该区域的指针。

答案 3 :(得分:1)

ptr仍然指向bytes的地址。或者,曾经被称为bytes的东西。即使你已经将bytes放入它自己的块中,并且变量在该块之外在语义上是不可访问的,但是在函数退出之前,内存会保持不变。这是一种典型的实现技术,但标准未定义,因此不要依赖它。

答案 4 :(得分:0)

ptr = (MyRect*)bytes;

“bytes”是内存中数组的地址。

ptr在此代码中分配了该地址。

演员告诉编译器忽略数据类型的差异。

如果你详细了解编译器在幕后做了什么,这当然可以正常工作。唯一的问题是更改编译器或编译器设置可能会导致此代码失败。它可能有点脆弱。

答案 5 :(得分:0)

它的工作原理是因为虽然'bytes'数组超出了范围,但是当你调用printf()时,它所驻留的堆栈空间还没有被踩到。它也有效,因为虽然'mr'不是256字节大,但它后面的内存(在堆栈上)并不关心你是在读它。

C是一种非常松散,非类型安全的语言。指针可以指向任何内存位置,您可以转换为您喜欢的任何指针类型。

所以我同意,你的程序基本上是偶然的。但它确实如此,因为C允许用指针做一些疯狂的事情。