Type safety for complex arithmetic in C99

137 Views Asked by At

I'm using C's complex arithmetic support and ran into some surprising and undesirable behavior. Complex values seem to be implicitly convertible to real ones, discarding the imaginary part.

Consider the following:

#include <complex.h>
#include <stdio.h>

float complex getComplex(float real, float imag)
{
    return real + imag * I;
}

int main()
{
    const float /* missing complex! */ c = getComplex(25, 6) / getComplex(2, 4);
    printf("%f + %f J\n", crealf(c), cimag(c));
    return 0;
}

I would expect to receive some warning that I am assigning a float complex to a float or perhaps calling crealf and cimagf on a non-complex value, but this builds cleanly on GCC 5.1, even with -Wall -Wextra -Wconversion switches. Clang 3.6.1 at least emits such a warning:

wut.c:11:62: warning: implicit conversion discards imaginary component: '_Complex float' to 'float'
      [-Wconversion]
    const float /* missing complex! */ c = getComplex(25, 6) / getComplex(2, 4);
                                       ~   ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~

Why can complex values "collapse" to real ones? Is there some verbiage about this in the standard? And is there some additional switch for GCC that can provide warnings about this behavior? It has already bitten us, and switching toolchains (to clang) for this project isn't feasible at present time.

1

There are 1 best solutions below

6
On BEST ANSWER

C11 final draft (N1570), 6.3.1.7 paragraph 2:

When a value of complex type is converted to a real type, the imaginary part of the complex value is discarded and the value of the real part is converted according to the conversion rules for the corresponding real type.

Real types are integer and real floating types.

The C99 rationale explains the motivation behind this:

In mathematics, when a complex is converted to real, the imaginary part is discarded. C99 follows the same convention.

And (numbering is identical to C11):

The specification in §6.3.1.6 and §6.3.1.7 match Fortran's.