tags:

views:

1464

answers:

4

Basically I would like to store the address of a pointer in a buffer. Don't ask me why

char * buff = "myBuff";
char * myData = (char*)malloc(sizeof(char*));
int addressOfArgTwo = (unsigned int)buff;
memcpy(myData, &addressOfArgTwo, sizeof(char*));

cout << "Int Val: " << addressOfArgTwo << endl;
cout << "Address in buffer:" << (unsigned int)*myData << endl;

I can't see why the above code doesn't work. It outputs:

Int Val: 4472832
Address in buffer:0

When the Int Val & Address in Buffer should be the same. thanks

+6  A: 

You dereference a char *, resulting in a char, and then cast that 1-byte char to an int, not the entire 4 bytes of address (if this is a 32-bit machine, 8 bytes on 64-bit). 4472832 is 444000 in hexadecimal. On a little-endian machine, you grab that last 00.

*((unsigned int*)myData)

should result in the correct number being displayed.

Michael
+1  A: 
Instead of (int)*myData, it should be *((int*)myData)
Igor Krivokon
+1  A: 

as Michael said this line should be

cout << "Address in buffer:" << *((unsigned int*)myData) << endl
oykuo
+1  A: 

This is generally dangerous:

 *((unsigned int*)myData)

Intel IA-32 (that everyone's used to) supports unaligned accesses, but some other architectures don't. They require variables to be aligned (8-bit data on 1-byte boundaries, 16-bit data on 2-byte boundaries, and 32-bit data on 4-byte boundaries). On an architecture that requires alignment, an unaligned access will either return corrupt data or throw a CPU exception. I've seen it cause a bug in real life at a past job, a subtle bug that caused file system corruption because of the disk driver that came with a software package we were using (on an embedded platform).

In this isolated case, you can see the address of myData came from malloc(), which should mean it's suitably aligned for all types of pointers, but casting a smaller pointer to a larger pointer is generally a dangerous practice if you don't know where the pointer came from.

The safe way to extract a 32-bit integer from an arbitrary memory location is to declare a temporary 32-bit integer and perform a copy to it, treating the source memory as a raw character array:

unsigned int GetUnalignedLittleEndianUInt32(void *address)
{
    unsigned char *uc_address = (unsigned char *)address;
    return (
        (uc_address[3] << 24) |
        (uc_address[2] << 16) |
        (uc_address[1] << 8) |
        uc_address[0]
    );
}

or more generally (with some function call overhead):

unsigned int GetUnalignedUInt32(void *address)
{
    unsigned int value;
    memcpy(&value, address, sizeof(value));
    return value;
}

which is actually just the reverse of the memcpy() you did to get the pointer there in the first place.

Although, treating the pointer as an int:

int addressOfArgTwo = (unsigned int)buff;

is also dangerous, if you're moving between 32-bit and 64-bit architectures, as Michael pointed out. Pointers aren't always 32-bit integers. Consider using a typedef that you can later change. The convention on Linux is for a pointer to be the same size as a long. On Windows, there are typedefs INT_PTR, UINT_PTR, LONG_PTR, and ULONG_PTR.

So, I would finally suggest (on Windows anyway):

ULONG_PTR GetAddressAtAddress(void *address)
{
    ULONG_PTR value;
    memcpy(&value, address, sizeof(value));
    return value;
}
Matthew