简体   繁体   中英

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;
}

I was just testing how to put a struct/class in an array of bytes, and was suprised when it compiled and worked, the printf prints all the values which i set in the mr variable.

just a little confused to what exactly "ptr" is pointing to? has it allocated memory for ptr somewhere?

It works by pure chance.

Firstly, you're basically making a byte-by-byte copy of the struct and placing it in a stack-allocated buffer using memcpy . However, you shouldn't do this in practice. It happened to work this time, because your struct is a POD (plain-old-data or C-struct), but if your struct was a C++ object with constructors/copy-constructors or what have you, you may have gotten a nasty surprise.

Secondly, the stack-allocated buffer containing the struct goes out of scope by the time you use it via your pointer, so what you're doing is totally undefined behavior . It only works by pure chance, and is not guaranteed to work again on a different computer or with a different compiler, or even at a different time of day.

Well, your program causes undefined behaviour, so you should probably not be surprised that it happens to work. Or if it happened to not work or caused the universe to end, for that matter. After your block containing the definition of bytes , ptr is out of scope, and may or may not still point to valid memory. In your case, it does. But you can't rely on that behaviour.

The unsigned char bytes[256] are allocated on the stack, ie everytime your function (in this case main ) is entered, 256 byte are reserved on the stack for the variable bytes . And through the cast ptr is now pointing to this area on the stack and interpreted as being of type MyRect . Since you first copied such a struct to the stack area this is all fine and valid. But as soon as you leave main , the area ptr points to is gone, so you may not store a pointer to that area outside of this function.

ptr is still pointing to the address of bytes . Or, what was once called bytes . Even though you've put bytes into its own block and the variable is semantically inaccessible outside of that block, the memory sticks around unmodified until the function exits. This is a typical implementation technique, but is undefined by the standard, so don't depend on it.

ptr = (MyRect*)bytes;

"bytes" is the address of the array in memory.

ptr gets assigned that address in this code.

The cast tells the compiler to ignore the difference in data types.

If you understand in detail what the compiler is doing under the covers this can certainly work just fine. The only problem is changing compilers or compiler settings might cause this code to fail. It can be a bit fragile.

It works because though the 'bytes' array is out of scope, the stack space it resides in is has not been stepped on by the time you call printf(). It also works because though 'mr' is not 256 bytes large, the memory following it (on the stack) doesn't care that you are reading it.

C is a very loose, non-type-safe language. Pointers can point to just about any memory location and you can cast to any pointer type you like.

So I agree, your program basically works by accident. But it does so, because C permits some wild things to be done with pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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