C99 complex support with visual studio

c, c99, complex-numbers, visual-studio

Solution

No matter what you do, you can't make "float complex" parse properly in a non-C99 compiler. So instead of writing that, make some typedefs. It's far easier if you only have to support one complex type, so I'll just demonstrate with `float complex`.

First, define the types:

#if __STDC_VERSION__ >= 199901L
//using a C99 compiler
#include <complex.h>
typedef float _Complex float_complex;
#else
typedef struct 
{
    float re, im;
} float_complex;
#endif

Then, we need to be able to create complex numbers, and emulate creal and cimag.

#if __STDC_VERSION__ >= 199901L
//creal, cimag already defined in complex.h

inline complex_float make_complex_float(float real, float imag)
{
   return real + imag * I;
}
#else
#define creal(z) ((z).re)
#define cimag(z) ((z).im)

extern const complex_float complex_i; //put in a translation unit somewhere
#define I complex_i
inline complex_float make_complex_float(float real, float imag)
{
    complex_float z = {real, imag};
    return z;
}
#endif

Next, write functions that wrap addition, subtraction, multiplication, division, and comparisons.

#if __STDC_VERSION__ >= 199901L
#define add_complex(a, b) ((a)+(b))
//similarly for other operations
#else //not C99
inline float_complex add_complex(float_complex a, float_complex b)
{
  float_complex z = {a.re + b.re, a.im + b.im};
  return z;
}
//similarly for subtract, multiply, divide, and comparison operations.

Note that `add_complex(c, 5)` doesn't work in C89 mode in the above code, because the compiler doesn't know how to make 5 into a complex. This is a tricky problem to fix in C without compiler support -- you have to resort to tricks like the new `tgmath.h` uses, which are compiler-specific.

Unfortunately, the effect of all of this is that the nice C99 syntax like `a+b` to add complex numbers has to be written `add_complex(a, b)`.

Another option (as another poster pointed to) is to use C++ `std::complex` on non-C99 compilers. This might be OK if you can wrap things in typedefs and `#ifdef`s. However, you'd require either C++ or C99.

Problem

I would like to use complex numbers as defined in C99, but I need to support compilers which do not support it (MS compilers come to mind). I don't need many functions, and implementing the needed functions on compilers without support is not too difficult. But I have a hard time implementing the 'type' itself. Ideally, I would like to do something like: ``` #ifndef HAVE_CREAL double creal(complex z) { /* .... */ } #endif #ifndef HAVE_CREALF float creal(float complex z) { /* ... */ } #endif ``` But I am not sure I see how to do this if the compiler cannot recognize 'float complex'. I would actually think it is impossible, but the C library by Dinkumware seems to indicate otherwise. What is the solution ? I don't mind using functions/macros for operations on the type, but I need a way to assign values to a complex number, and get back its real/imaginary part in a way whichi is compatible with C99. Solution I ended up doing something like this: ``` #ifdef USE_C99_COMPLEX #include <complex.h> typedef complex my_complex; #else typedef struct { double x, y; } my_complex; #endif /* * Those unions are used to convert a pointer of my_complex to native C99 * complex or our own complex type indenpendently on whether C99 complex * support is available */ #ifdef USE_C99_COMPLEX typedef union { my_complex my_z; complex c99_z; } __complex_to_c99_cast; #else typedef union { my_complex my_z; my_complex c99_z; } __complex_to_c99_cast; #endif ``` for the type definition, and as follows to define a set of complex functions: ``` #ifndef HAVE_CREAL double my_creal(my_complex z) { union { my_complex z; double a[2]; } z1; z1.z = z; return z1.a[0]; } #endif #ifdef HAVE_CREAL my_complex my_creal(ny_complex z) { __complex_to_c99_cast z1; __complex_to_c99_cast ret; z1.my_z = z; ret.c99_z = creal(z1.c99_z); return ret.npy_z; } #endif ``` That's a bit complicated, but this enables me to easily reuse C lib functions when available, and it can be partly automated through code generator.

Original source