1

Pointer Downcast

    int* ptrInt;
    char * ptrChar;
    void* ptrVoid;
    unsigned char indx;
    int sample = 0x12345678;

    ptrInt = &sample;
    ptrVoid = (void *)(ptrInt);
    ptrChar = (char *)(ptrVoid);

    /*manipulating ptrChar */
    for (indx = 0; indx < 4; indx++)
    {
        printf ("\n Value: %x \t Address: %p", *(ptrChar + indx), ( ptrChar + indx)); 
    }

Output:

 Value: 00000078         Address: 0022FF74
 Value: 00000056         Address: 0022FF75
 Value: 00000034         Address: 0022FF76
 Value: 00000012         Address: 0022FF77

Question: Why was sample divided into char sized data? And when pointer arithmetic is performed, how was it able to get its remaining value? How this was possible?


Pointer Upcast

unsigned int * ptrUint;
void * ptrVoid;
unsigned char sample = 0x08;

ptrVoid = (void *)&sample;
ptrUint = (unsigned int *) ptrVoid;

printf(" \n &sample: %p \t ptrUint: %p ", &sample, ptrUint );
printf(" \n sample: %p \t *ptrUint: %p ", sample, *ptrUint );  

Output:

 &sample: 0022FF6F       ptrUint: 0022FF6F
 sample: 00000008        *ptrUint: 22FF6F08    <- Problem Point

Question: Why is it that there is a garbage value in *ptrUint? Why is the garbage value similar to ptrUint? Should malloc() or calloc() be used to avoid this garbage value? What kind of remedy would you suggest to remove the garbage value?

Bogdan Vasilescu
  • 407
  • 4
  • 22

3 Answers3

1

In the first example, you are using a char pointer so the data is going to be accessed a byte at a time. Memory is byte addressable, so when you add one to a pointer, you will access the next higher memory address. This is what is happening with the for loop. Using a byte pointer tells the compiler to access only the single byte, and rest of bits will show up as 0 when you are printing with %p.

In the second example, I think what is happening is that one byte is allocated for the sample byte, then the following 4 bytes were allocated to the ptrUint. So when you get the value starting at the memory address of sample and converting it to a 4 byte pointer, you just see the value in Sample plus the first 3 bytes of the ptrUint. If you cast this to a char pointer, and print, you would only see 8 in the output.

user623879
  • 4,066
  • 9
  • 38
  • 53
  • Oh, so you mean to say that in the first sample, there is no possibility that *(ptrChar + indx), will have a garbage value. OK, that makes a lot of sense. But why did *(ptrChar + 0) started with 0x78? For the second sample, I was wondering why the compiler added garbage value, because if we do `(unsigned int)(charTypeVariable);`charTypeVariable will only widen the data with 0's to make it fit to an unsigned int. Is this different when dealing with pointer variables? – Amirah Reyna Jul 03 '11 at 07:58
  • That is the way bytes are ordered in little endian(x86) systems. The least significant byte is at the lowest memory address. In this case 0x78 is the least significant byte in the word you initialized to sample. APPLE computers on the other hand are big endian, so it would have printed reverse on such a system. – user623879 Jul 03 '11 at 08:09
  • Also, if there is no way to remove the garbage values. Masking `*ptrUint & 0x000000ff;` can be made? – Amirah Reyna Jul 03 '11 at 08:15
  • The compiler did not add a garbage value. It is just making use of all the memory it can. When you create a unsigned char, you are allocating 8 bits. Then you also have allocated some pointers in the same context so the compiler is likely to put allocate all those variables contiguously. This is what you are seeing when you cast the char to a unsigned int and print it...you are seeing the pointer variable's(ptrUint) upper 3 bytes of what it is pointing to, which you effectively set to the address of sample – user623879 Jul 03 '11 at 08:16
  • what are you even trying to print in this line printf(" \n sample: %p \t *ptrUint: %p ", sample, *ptrUint ); – user623879 Jul 03 '11 at 08:18
  • *ptrUint & 0x000000ff; If you are just trying to print the lower byte, why not just print sample. Alternatively, you could cast to unsigned char lol...*(unsigned char*)ptrUint; – user623879 Jul 03 '11 at 08:22
  • OK, I got it. I may be needing some reading on memory allocation. Thanks anyways. I was cleared. – Amirah Reyna Jul 03 '11 at 08:58
0

These aren't upcasts and downcasts, that would imply some kind of inheritance hierarchy.

In your first example you treat a pointer to an integer like if it was a pointer to char(s). Incrementing a pointer to int adds 4 to it, incrementing a pointer to char adds 1 to it (assuming 32 bit ints and 8 bit chars). Dereferencing them makes an int and a char, respectively. Hence the fragmentation into bytes.

In your second example you treat the unsigned char variable called sample as if it were a pointer to int, and dereference it. You are essentially reading garbage from the 0x08 memory address. I suppose you forgot a &. You are also passing a 1 byte char and a 4 byte int to the second printf, instead of 4+4 bytes, that messes up printf, reading 3 bytes more from the stack than you have given him. Which coincidentally is part of the ptrUint value given to the first call of printf. Using %c instead of %p should fix it.

Frigo
  • 1,709
  • 1
  • 14
  • 32
0

The other answers have already explained why you're seeing what you're seeing.

I will add that your second example relies on undefined behaviour. It is not valid to dereference an int * that points to data that wasn't originally an int. i.e.:

char x = 5;
int *p = (int *)&x;
printf("%d\n", *p);  // undefined behaviour
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680