tags:

views:

131

answers:

6
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?

+2  A: 

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.

Carl Norum
I agree with James. Especially since most compiler will most likely happily reserve the corresponding space in the stack frame as if there were no subscope.
DarkDust
@Carl: Not explaining why the memory should be invalid after the block :-)
DarkDust
+9  A: 

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.

Charles Salvia
Also, another cause of undefined behavior is that you are copying 256 bytes, when the size of your struct is only around 116 bytes (give or take depending on the implementation.) So you're probably copying half of your call stack into the buffer, resulting in yet more hilarious undefined behavior.
Charles Salvia
oops, i thought that argument took the size of the destination,
The size argument to memcpy refers to the number of bytes to copy, meaning that it will attempt to read that many bytes from the source, and write that many bytes to the destination.
Charles Salvia
@Charles Salvia, I really laughed at, `more hilarious undefined behavior`. You made my day better, thanks. :-)
Yossarian
+2  A: 

The unsigned char bytes[256] are allocated on the stack, i.e. 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.

DarkDust
A: 
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.

Jay
+1  A: 

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.

Steve M
A: 

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.

Les