0

I'm working my way through some old cross-platform C code. The code uses a number of variables defined like this:

complex double *cur; /* Amplitude of basis function */

This line compiles fine on OSX and iOS, but in VS I get two errors:

invalid combination of type specifiers

appears on the "double". I suspect this is not really an error and the real problem is:

identifier _complex is undefined

which appears on the word "complex". When I right-click and get the definition, I go to math.h as I would expect, and find this definition:

#ifndef _COMPLEX_DEFINED
    #define _COMPLEX_DEFINED

    struct _complex
    {
        double x, y; // real and imaginary parts
    };

    #if !__STDC__ && !defined __cplusplus
        // Non-ANSI name for compatibility
        #define complex _complex
    #endif
#endif

The thing I don't get is how does it even recognize complex as an alias for _complex if this code didn't work properly?

Poking about here on SO I found this thread. It suggests using _Dcomplex from complex.h for these variables. Is that correct? If so, what is this complex in math.h?

In any event, this code has to be cross-platform. Is there a way I can #define a way for this to work on VS as well as other systems?

Maury Markowitz
  • 9,082
  • 11
  • 46
  • 98

2 Answers2

0

As you can see in the code _complex is structure. complex is macro defined for _complex (When C++ provided support for complex type).

Now, when you are writing complex double *cur; then it is expanded as _complex double *cur;. So VC++ compiler is confused about the type of *cur i.e. it is of type complex or double.

To solve this issue (and keep your code the platform independent) do following:

#ifdef __VCPP__
     _complex
#else
     complex double 
#endif    
   *cur; /* Amplitude of basis function */

Note: Define __VCPP__ macro if plateform is Windows.

UPDATED: Both, __STDC__ and __cplusplus are pre-defined. See here for Standard predefined identifier by VS, the list of pre-defined macros.
Since __STDC__ and __cplusplus are defined, hence the macro condition #if !__STDC__ && !defined __cplusplus is evaluated to false. Hence complex is not available.

To solve the problem, You can use _complex.

cse
  • 4,066
  • 2
  • 20
  • 37
  • If I understand what you are doing here, it is effectively just removing "double" when it's open in VC. Is that correct? If so, I tried simply removing "double" and that did not work, same error on "complex". – Maury Markowitz Mar 01 '18 at 17:52
  • Yes... You got me, Which VS version are you using? Also check if `__STDC__` and `__cplusplus` are defined or not. – cse Mar 01 '18 at 17:56
  • I'm on VS2017 Community. Is there a simple way to check if those are defined? – Maury Markowitz Mar 01 '18 at 17:58
  • You can use `#ifdef __STDC__` \n `cout<<"__STDC__ defined";` and so. – cse Mar 01 '18 at 18:02
  • Thanks cse, it turns out __STDC__ is defined in certain cases but not others (depending on switches). However, testing _MSC_VER seems to do the trick. – Maury Markowitz Mar 01 '18 at 18:08
  • Yes, Both `__STDC__` and `__cplusplus` are pre-defined See [here for _Standard predefined identifier by VS_](https://msdn.microsoft.com/en-us/library/b0084kay.aspx), the list of pre-defined macros. – cse Mar 01 '18 at 18:10
  • The *value* of `__STDC__` indicates which version of the standard a compiler claims to conform to. For C89/C90, it's `1`. For C99, it's `199901L`. For C11, it's `201112L`. `_Complex` should be available if `__STDC__` is defined and its value is greater than or equal to `199901L`. – Keith Thompson Mar 01 '18 at 19:26
0

For portability, one approach is to define a type that varies in its definition per the compiler.

Since C99, complex types are specified as float _Complex, double _Complex, long double _Complex. "Complex types are a conditional feature that implementations need not support." §6.2.5 11

If code is compiled with a non-compliant C99 compiler, use its supplied complex type.

#ifndef MM_COMPLEX_DEFINED
  #ifdef __STDC_VERSION__
    #if __STDC_VERSION__ >= 199901L
      #if __STDC_NO_COMPLEX__ != 1
        #define MM_COMPLEX_DEFINED
        typedef double _Complex complex_double;
...

#ifndef MM_COMPLEX_DEFINED
  // Use macro processing as needed per other compilers
  #ifdef _MSC_VER 
    #define MM_COMPLEX_DEFINED
    typedef complex complex_double;
... 

#ifndef MM_COMPLEX_DEFINED
  ...

For portability outside C99/C11, additional code may be needed to access the real and imaginary parts of the complex type. Likely many aspects of portably using a complex floating point type will require wrapper functions.


See
Compiling C code in Visual Studio 2013 with complex.h library
How to Detect if I'm Compiling Code With Visual Studio 2008?
Is there a preprocessor macro to detect C99 across platforms?
Where are C11 optional feature macros?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • is there a reason you use typedef in the definitions, rather than #define? if I use #define, could I do something like #define complex _C_double_complex and then just use "complex *x;"? – Maury Markowitz Mar 01 '18 at 19:34
  • @MauryMarkowitz Yes, a typedef is better. Yes you could use a `#define`. I recommend to not use "complex" as the type name or as a `#define` name. 1) It will certainly have trouble in the name space - use a name that will not appear in any target platform implementation of the complex type. 2) `complex var` looks wrong with modern C. – chux - Reinstate Monica Mar 01 '18 at 19:40
  • Ok, all good. One last question on this. Given that there are hundreds of these lines, I could just search/replace with the new name. But is there any way to preserve the original "complex double" so I don't have to do edits in files I'd rather stay out of? As you say it looks old, but looks << bugs! – Maury Markowitz Mar 01 '18 at 19:51
  • @MauryMarkowitz There are always some way to do it as you want. To be clear, I am recommending against `complex var1` (no `double` in that). Now consider `complex double var2` with the MS compiler, that look wrong too as `complex var2` is expected. For _portable_ code to C99/VS, I am confident that you will need something that looks like neither. Try this: re-code a small portion as you see best and post on https://codereview.stackexchange.com and see what many folks think. – chux - Reinstate Monica Mar 01 '18 at 20:09
  • BTW: With C99 the order of the 2 words `double` `_Complex` makes no difference. If `` included, code can use `complex` rather than `_Complex`. – chux - Reinstate Monica Mar 01 '18 at 20:12
  • Ok, so if the order is not important, and "complex double var" is correct C99, and I'm importing , what the heck IS wrong? It should work as-is! This gives me an idea... – Maury Markowitz Mar 01 '18 at 21:33
  • @MauryMarkowitz Note that VS is not necessarily C99 compliant. BTW, are you doing C or C++? "importing " hints at C++. – chux - Reinstate Monica Mar 01 '18 at 21:37
  • Pure C. I think the problem here is that STDC is *not defined*, as cse eludes to. To get it to turn on, I need to specify /Za, but in makefile projects there doesn't appear to be a place to do it! – Maury Markowitz Mar 01 '18 at 21:43
  • chux, my apologies, I needed to re-read the original thread more closely before replying. As you guessed, VC is simply NOT C99 compliant. I'll have to implement something like what you suggest, which is really so annoying! – Maury Markowitz Mar 01 '18 at 22:21