Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is casting an array to a homogeneous struct portable in C?

Tags:

c

struct

Consider the following homogeneous struct:

struct myStruct {
    void* a;
    char* b;
    int* c;
};

It is homogeneous, I believe, because all of the datatypes are pointers.

Given this struct would the following code be valid and portable across C99?

int main()
{
    void* x = NULL;
    char* y = "hello";
    int* z = malloc(sizeof(int) * 10);
    z[2] = 10;

    void** myArray = malloc(sizeof(void*) * 3);
    myArray[0] = x;
    myArray[1] = y;
    myArray[2] = z;

    struct myStruct* s = (struct myStruct*)myArray;

    printf("%p %s %d\n", s->a, s->b, s->c[2]);

    return 0;
}

I understand that structs will often add padding between components in order to keep the size of the struct consistent, however, because the types of the pointers are all the same, is it a safe assumption that no padding will be added? I'm not necessarily asking if there is a 100% guarantee (I understand this is completely implementation specific, and that a compiler could add padding for obscure reasons), more I am asking for what reasons padding might be added to a homogeneous struct, if any reasons at all.

like image 305
Braden Steffaniak Avatar asked Mar 21 '17 07:03

Braden Steffaniak


2 Answers

The code violates aliasing rules. The types void* and struct myStruct are not compatible, and no exceptions apply in this case. The dereference of the struct pointer in the printf statement causes undefined behavior:

printf("%p %s %d\n", s->a, s->b, s->c[2]);

This is true even if the structure has the same size as three void pointers, has no padding, and has the same alignment requirements.

like image 26
2501 Avatar answered Nov 15 '22 23:11

2501


No it's not portable. The size of pointers may actually differ which means there may be padding in your structure.

On most modern platforms this won't be a problem, but there's nothing in the standard that says all pointers have to be equal in size. Only that pointers are implicitly convertible from and to void *.

A good example of a platform where pointer sizes differs is DOS (which is still actively used, for example on embedded systems) and other 16-bit segmented systems.

like image 115
Some programmer dude Avatar answered Nov 15 '22 23:11

Some programmer dude