Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
578 views
in Technique[技术] by (71.8m points)

c++ and <complex.h> with <complex> in separate files

Notes:

I am compiling on OSX using Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)

Specifically, I am trying to compile a monolithic source from LibIIR, a filter library maintained here by Laurence Withers.

I've already looked at this answer here about using both <complex> and <complex.h> in the same file.


Setup:

I have a file iir.h like so:

#include <complex.h>

#ifdef __cplusplus
extern "C" {
#endif

...

I have C++ source and header files libiir++.cpp and iir++.h like so:

/*** libiir++.cpp ***/
// we need to include "iir.h" first, as it pulls in <complex.h>, which we need
// to take effect before "iir++.h" pulls in <complex>
#include "iir.h"

// now remove the preprocessor definition of complex to _Complex, which is fine
// for the C header but not good for the C++ header
#undef complex

#include "iir++.h"

namespace IIR {

...

-

/*** iir++.h ***/
#include <complex>

namespace IIR {

...

Problem:

clang gives me the following error when compiling:

./iir.h:570:15: error: expected ';' after top level declarator
double complex iir_response_c(const struct iir_coeff_t* coeff, double freq);
              ^
              ;

Evidently, the new <complex> import is not happening--or #undef complex is happening again--but I don't see how. Any advice on what might be going wrong, or what to check?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

<complex.h> is a C header and it is not compatible with C++.

C++ defines C library compatibility through headers named in the pattern <c***>. So, the C++ counterpart to <complex.h> is named <ccomplex>. Here's what the C++ standard has to say about that:

Header <ccomplex>

The header behaves as if it simply includes the header <complex>.

If you attempt to use the C complex number library, you just get the C++ one instead.

Bottom line: you simply cannot run C complex math through a C++ compiler. At best, you can use the preprocessor to generate equivalent programs depending on __cplusplus.

For example,

#if __cplusplus
#   include <complex>
    typedef std::complex< double > cdouble;
#else
#   include <complex.h>
    typedef double complex cdouble;
#endif

Note, std::complex< double > and double complex are layout-compatible per C++14 [complex.numbers] §26.4/4 and C11 §6.2.5/13. The intent seems to be that you can use cdouble for cross-language function prototypes, although strictly speaking it depends on the ABI.


Incidentally, the C++ standard does define what happens when you #include <complex.h>, but it doesn't make any sense:

Every C header, each of which has a name of the form name.h, behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope. It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).

So, #include <complex.h> should give you a global ::complex<T>. This is a defect in the standard.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...