gislibergur
gislibergur

Reputation: 141

C, Creating a 32 bit pointer to a 8 bit array

I have a buffer where each entry in the buffer is 8 bits in size:

uint8_t Buffer[10] = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};

What I need to do is to create pointers to that array, for example 16 bit and 32 bit pointers. For example:

uint32_t *x;
x = Buffer;

uint32_t *y;
y = Buffer+4;

uint16_t *z;
z = Buffer+8;

Where each variable would then read from the array, for example:

x = 0x78563412
y = 0xf4f3f2f1
z = 0xf6f5

This works completely fine, the problem is that I'm getting warnings about incompatible pointer types. So I was wondering if there is an alternative way of doing this or if I'll just have to live with the warnings? Or am I simply doing this completely the wrong way?

Please note that this code will be executed on a single type of platform where the endianness is always the same and the size of data types is always the same.

Upvotes: 4

Views: 10462

Answers (3)

Cornstalks
Cornstalks

Reputation: 38218

You should heed the warnings; what you're doing is undefined behavior. Type aliasing like that is undefined behavior, particularly since there is no guarantee that Buffer has the correct alignment such that it can be accessed as an int/short. If Buffer has the correct alignment, then you can just explicitly cast and it's okay (and the warning will go away).

You have two options:

One, you align the buffer as the larger of the two types. Be careful that your pointer arithmetic doesn't throw off the alignment:

#include <stdalign.h>

alignas(int) unsigned char Buffer[10] = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};

unsigned int *x;
x = (unsigned int*)(Buffer);

unsigned int *y;
y = (unsigned int*)(Buffer+4);

unsigned short *z;
z = (unsigned short*)(Buffer+8);

Two, you create an unsigned int/unsigned short variable and then memcpy the bytes you're interested in into the variable:

unsigned int x;
memcpy(&x, Buffer, 4);

unsigned int y;
memcpy(&y, Buffer + 4, 4);

unsigned short z;
memcpy(&z, Buffer + 8, 2);

Upvotes: 7

Djole
Djole

Reputation: 1145

You might want to use a union

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

typedef union{

    uint8_t Buffer[10];
    struct{
        uint32_t x;
        uint32_t y;
        uint16_t z;
    };

}MYSTRUCT;


int main(){

    MYSTRUCT b = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};

    printf("x=%#x y=%#x z=%#x\n",b.x,b.y,b.z);

 return 0;

}

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

The problem with your approach is that it assumes a particular endianness of underlying hardware. Different computers will interpret a sequence of hex bytes

01 23 45 67

as eiter

01234567 or 67452301

Your program may compile and run on both systems, but since the result is hardware-specific, the compiler must warn you of the possibility.

The proper way of forcing a particular endianness is by using an array of integers, convert them using hton and ntoh functions, and set individual bytes either directly by casting a pointer to unsigned char*, or with memcpy.

Upvotes: 2

Related Questions