13

The following code compiles and runs just fine in C (at least according to 'gcc -std=gnu99'), but it fails to compile under C++, giving "line 5: error: cannot convert 'double' to 'double complex' in initialization". Does anybody know why?

#include "/usr/include/complex.h"
#include <stdio.h>

int main(int argc, char * argv[]) {
  double complex a = 3;  // ERROR ON THIS LINE
  printf("%lf\n", creal(a));
  return 0;
}

I realize there is another way of doing complex numbers in C++, but I have to use C complex numbers in C++, because that is how the legacy code I was given does things. Thanks if you can help!

iloveponies
  • 175
  • 1
  • 1
  • 8
  • 5
    But really, _why_ don't you want to use [`std::complex<>`](http://en.cppreference.com/w/cpp/numeric/complex)? – ildjarn May 10 '12 at 18:39
  • 3
    FTR, `-std=gnu99` is not really the flag you want for **C**. That's "C with stuff GNU thought would be a good idea, but whether it is or not is up for interpretation". `-std=c99` is desirable if you want **C**. – R. Martinho Fernandes May 10 '12 at 18:43
  • 1
    ildjarn: Unfortunately, the library I am working with uses C99 complex numbers in C++. It does not seem wise to start a project this way, but this is the code I have to work with. Martinho: that's true. I should have done the test with -std=c99 – iloveponies May 10 '12 at 19:46

3 Answers3

19

A C++ compiler could choose to support the _Complex keyword as an extension (and a few do), but that isn't portable. If you want to have a portable C++ solution, you need to use the C++ std::complex templates, unfortunately.

The good news is that C++ std::complex numbers are guaranteed to be compatible with C complex numbers (in the sense that a pointer to one can always be converted to a pointer to the other, and the right thing will happen), which means that if you need to interoperate with a C library that expects C complex values, you won't have any trouble.

C11:

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.

C++11:

If z is an lvalue expression of type cv std::complex<T> then:

— the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,

reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and

reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • Where is that guarantee ("C++ std::complex numbers are guaranteed to be compatible with C99 complex numbers")? The response below (http://stackoverflow.com/a/10540288/2189128) cites a non-canonical source (Wikipedia) that say the opposite. – Jeff Hammond Jan 08 '16 at 23:16
  • 2
    @Jeff: The wikipedia link doesn't actually contradict my claim; they are different types, but are guaranteed to have the same memory layout and alignment requirements. I added the appropriate references to my answer. – Stephen Canon Jan 11 '16 at 17:49
  • The Chapter and verse on this is "29.5 Complex numbers [complex.numbers]" note 4: If `z` is an lvalue expr of type cv `complex` then: the expr `reinterpret_cast(z)` , `reinterpret_cast(z)[0]` is the real part of `z`, and `reinterpret_cast(z)[1]` is the imag part of `z`. , if `a` is an expr of type cv `complex*` and the expr `a[i]` is well-defined for an integer expr `i`, then: `reinterpret_cast(a)[2*i]` shall designate the real part of `a[i]`, and `reinterpret_cast(a)[2*i + 1]` shall designate the imaginary part of `a[i]`. – emsr Apr 12 '18 at 15:04
10

Use the C keyword for complex: _Complex. C++ uses complex as a (template) class. I'm not sure where creal is or I would uncomment that.

#include <complex.h>
#include <cstdio>

int main(int argc, char * argv[]) {
  double _Complex a = 3.0 + 0.0I;  // DECLARATION WORKS NOW - NOTE ASSIGNMENT MUST HAVE IMAG PART
  //printf("%lf\n", creal(a));
  return 0;
}

This works in gcc (I compiled with g++). I got a warning about deprecated .h headers.

Here is a link to an email trail showing nonstandard compatibility with C++ and C with complex numbers. C++11 requires layout compatibility of C++ complexes with C _Complexes.

I'm currently investigating creal, etc. in C++. I'm not finding anything in the standard. Since there seems to be some effort to provide some source compatibility between C++ and C then creal, cpow, etc. might make a nice addition to TR2 the library proposals.

emsr
  • 15,539
  • 6
  • 49
  • 62
  • THANK YOU!!!!! From what you said, I was able to get the solution. Stack Overflow is not allowing me to post the solution yet, but it's that you have to add the imaginary part to the assignment. – iloveponies May 10 '12 at 19:49
  • As of this comments writing date/time, the above code produces a compiler error, `unable to find numeric literal operator ‘operator"" I`, a newer `g++` version 4.8.x. Most likely the newer `g++` version is more standards compliant and so errors out on this syntax. I also tried the `_Complex_I` but that did not compile either on `g++`. – Trevor Boyd Smith Apr 12 '18 at 14:37
  • 1
    You can compile the code if you don't try to initialize... or set the variable. Which means your ability to use c style complex datatypes with a c++ compiler is... limited. If you want to use complex numeric processing in C++, I think the recommended solution is to use `std::complex<>`. If you are forced to use C code, then you are forced to use C99's complex types and functionality presented by ``. --> or to put it another way just read @StephenCanon's answer :) (i.e. use `std::complex`). – Trevor Boyd Smith Apr 12 '18 at 14:40
  • @TrevorBoydSmith I agree that std::complex is by far preferable. The OP was concerned about compiling C code with C++. The initialization can be recovered by defining a capital 'I' literal operator. (You'll get warns about missing underscore in user-space literal op.) Also note that `std::complex z; static_cast(z)` is a requirement for std::complex to overlap with other language's complex. Ugly but true. – emsr Apr 12 '18 at 14:56
  • I added the correct std reference and syntax as a comment to @StephenCanon's answer below. – emsr Apr 12 '18 at 15:10
9

Compatibility of C and C++

Several additions of C99 are not supported in C++ or conflict with C++ features, such as variadic macros, compound literals, designated initializers, variable-length arrays, and native complex-number types. The long long int datatype and restrict qualifier defined in C99 are not included in the current C++ standard, but some compilers such as the GNU Compiler Collection[4] provide them as an extension. The long long datatype along with variadic templates, with which some functionality of variadic macros can be achieved, are present in the new C++ standard, C++11. On the other hand, C99 has reduced some other incompatibilities by incorporating C++ features such as // comments and mixed declarations and code.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192