Home > Software design >  Is it possible to subscript into a uint64_t pointer in C?
Is it possible to subscript into a uint64_t pointer in C?

Time:06-16

I'm a C beginner. Having trouble understanding whats happening with this code:

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

int main(void)
{
    uint64_t num = 99999;
    uint64_t *num_ptr = &num;

    uint8_t first_byte = ((uint8_t *)num_ptr)[0];

    printf("%hhu", first_byte);

    return 0;
}

This prints 159.

I'm looking at uint8_t first_byte = ((uint8_t *)num_ptr)[0];

I'm trying to understand it this way: the uint64_t pointer num_ptr is first cast as a uint8_t pointer, then we index into it with the square brackets to get the first byte. Is this a correct explanation? If so is it possible to index into pointers to get their partial contents without dereferencing?

CodePudding user response:

Consider a work-alike program:

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

typedef union _U64_t
{
    uint64_t whole;
    uint8_t  parts[sizeof(uint64_t)];
} U64_t;


int main( int argc, char **argv )
{
    U64_t number;
    number.whole = 99999;

    printf( "number.parts[0] is %u / 0xx\n", number.parts[0], number.parts[0] );

    return 0;
}

Which outputs:

number.parts[0] is 159 / 0x9f

Here with a C union, it's simulating what was done in the OP's code. The .parts covers the same memory as the .whole. So in essence the parts is giving access to the content of the uint64_t's bytes-in-memory without any sort of pointer dereference.

This sort of operation will have issues with portability due to endianness, and should generally be avoided. Of course one could mitigate this by packing into network-byte-order with functions like htonl(), so a known order is preserved.

CodePudding user response:

  1. What you do is a "pointer punning". Generally it is a dangerous operation, might invoke Undefined Behavior and violate strict aliasing rule. But when you access other data as chars it is OK.
int main(void)
{
    uint64_t num = 99999;
    uint64_t *num_ptr = &num;

    printf("6"PRIx64"\n", num);

    for(size_t index = 0; index < sizeof(num); index  )
    {
        printf("Index = %2zu, value= hhx\n", index, ((unsigned char *)num_ptr)[index]);
    }
    return 0;
}

The safest method is to use memcpy

int main(void)
{
    uint64_t num = 99999;
    uint64_t *num_ptr = &num;

    unsigned char arr[sizeof(num)];

    printf("6"PRIx64"\n", num);

    memcpy(arr, &num, sizeof(num));

    for(size_t index = 0; index < sizeof(num); index  )
    {
        printf("Index = %2zu, value= hhx\n", index, arr[index]);
    }
    return 0;
}
  • Related