繁体   English   中英

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

[英]How does this work? copying anything into an array of bytes (chars)

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分配了内存吗?

它纯粹的机会。

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

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

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

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

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

ptr = (MyRect*)bytes;

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM