~/articles/c-void-pointer

Demonstration

Here's snippet of code for the demonstration:

#include <stdint.h>
#include <stdio.h>

int main()
{
    uint32_t a = 0xAABBCCDD;
    void*    p = &a;

    printf("a(decimal): %u\n", a);
    printf("a(hex): %X\n", a);
    printf("memory layout:\n");
    for (size_t i = 0; i < 4; i++) {
        // a is four bytes long
        printf("offset: %zd\taddr.: %p\tvalue: %hhX\n", i, (p + i), *(uint8_t*)(p + i));
    }
    printf("*(int8_t*)p:\t%hhX\n", *(int8_t*)p);
    printf("*(int16_t*)p:\t%hX\n", *(int16_t*)p);
    printf("*(int32_t*)p:\t%X\n", *(int32_t*)p);
    printf("*(uint8_t*)p:\t%hhX\n", *(uint8_t*)p);
    printf("*(uint16_t*)p:\t%hX\n", *(uint16_t*)p);
    printf("*(uint32_t*)p:\t%X\n", *(uint32_t*)p);

    return 0;
}

The snippet generates this output

a(decimal): 2864434397
a(hex): AABBCCDD
memory layout:
offset: 0       addr.: 0x16dd34ab8      value: DD
offset: 1       addr.: 0x16dd34ab9      value: CC
offset: 2       addr.: 0x16dd34aba      value: BB
offset: 3       addr.: 0x16dd34abb      value: AA
*(int8_t*)p:    DD
*(int16_t*)p:   CCDD
*(int32_t*)p:   AABBCCDD
*(uint8_t*)p:   DD
*(uint16_t*)p:  CCDD
*(uint32_t*)p:  AABBCCDD

We can see that in the memory section, going forward in the index would result in reading the memory backwards: my laptop is little endian!

Note that I used the %hhX and %hX specifier for printing numbers smaller than 32 bits (4 bytes). Without the hh prefix, %X wouldn't be able to know how big the number is. This would especially cause problems for signed integers, as the maximum number has to be known to calculate the two's complement.

Conclusion

Void pointers void* requires you to cast them to a type before you use them. This is done so that the C compiler can know what type the pointer will be dereferenced to; without this information, the C compiler wouldn't be able to determine the type, hence the length in memory (in bytes) that this pointer points to. Derefencing a void* is indeed not allowed by the C compiler, doing so would generate an error.

This experiment shows that, by casting void* into different pointer types and then dereferce them, you can "trick" the computer into reading the variables differently.

<newer   earlier>