cstrict-aliasing

Strict aliasing between Complex numbers and real numbers in C


Suppose I have a following code


#include <complex.h>
#include <stdio.h>
int main()
{
    double _Complex a  = 1.0;
    void * b = &a;
    double * c = b;
    c[0] = 3;
    c[1]  = 2;
    printf("%f %f\n",creal(a), cimag(a));
    return 0;
}

Does the C standard mandate that a is changed in this case (Can compilers assume a is unchanged in this case)? I see most compilers are fine but not sure if this is allowed by standard.


Solution

  • While c[0] = 3; and c[1] = 2; nominally violate the strict aliasing rules in C 2024 6.5.1 because they access the double _Complex object a with an lvalue of type double, 6.2.5 states:

    … Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number…

    This phrasing about the “same representation” is used multiple times in the standard with the intent, according to notes, that it makes the two types interchangeable in some vague way that the standard does not define. This conflicting information between aliasing and interchangeability is a long-standing defect in the C standard, and one might interpret the interchangeability as overriding or coming before the aliasing rules.

    However, it is safer to take the “same representation” requirement to mean you can rely on the memory layout of the double _Complex type to have the same layout as two double objects which can be aliased through character type:

    memcpy(&c[0], & (double) {3}, sizeof c[0]);
    memcpy(&c[1], & (double) {2}, sizeof c[1]);
    

    or by using a union:

    union { double _Complex a; double b[2]; } u = { 1.0 };
    u.b[0] = 3;
    u.b[1] = 2;