Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Portability concerns on C struct/union

Supposing I have the following type from an external library:

union foreign_t {
    struct {
        enum enum_t an_enum;
        int an_int;
    } header;
    struct {
        double x, y;
    } point;
};

is it safe to assume the following code fragment will work as expected on different platforms and with different compilers?

struct pair_t {
    double x, y;
};

union foreign_t foreign;
struct pair_t *p_pair;

p_pair = (struct pair_t *) &foreign;
p_pair->x = 1234;
p_pair->y = 4321;

/* Expected result: (1234, 4321) or something like that */
printf("(%lf, %lf)", foreign.point.x, foreign.point.y);

EDIT:

Following the strict aliasing suggestion I made the following test:

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

int main()
{
    uint16_t word = 0xabcd;
    uint8_t tmp;
    struct {
        uint8_t low;
        uint8_t high;
    } *byte = (void *) &word;

    tmp = byte->low;
    byte->low = byte->high;
    byte->high = tmp;

    printf("%x\n", word);

    return 0;
}

The above apparently innocent piece of code is not reliable:

$ gcc -O3 -fno-strict-aliasing -otest test.c
$ ./test
cdab
$ gcc -O3 -fstrict-aliasing -otest test.c
$ ./test
abcd

No peace for developers...

like image 263
ntd Avatar asked Oct 27 '25 04:10

ntd


2 Answers

As you have written it, I believe it should work with virtually any compiler on any architecture. However, I do think it technically violates the strict aliasing rules. You're casting between unrelated pointer types, so an overly aggressive optimizer might reorder certain memory reads and writes because it assumes that certain pointers won't alias each other.

Unfortunately, I don't think there's a way to make this code absolutely bulletproof against strict aliasing, assuming that you can't modify the definition of foreign_t. Since the inner struct doesn't have a name, there's no way you can construct a pointer to it that the compiler will assume is aliasable. In practice, though, I don't think you'll see problems with your code.

like image 185
Adam Rosenfield Avatar answered Oct 29 '25 19:10

Adam Rosenfield


Yes that should be perfectly portable. The fact that foreign is a union never even comes into it, since you never use it as a header.

(You can't write to header and then read from point and expect it to work the same on all platforms. But then, you don't want to do that, so you should be fine.)

like image 44
alex tingle Avatar answered Oct 29 '25 17:10

alex tingle



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!