How to include C11 headers when compiling C++ with GCC? - c++

In a C++ project, I'm using a C library which includes some C11 headers. It won't compile with GCC. See this simple code:
// main.cc
#include <stdatomic.h>
int main()
{
return 0;
}
Running gcc main.cc -lstdc++, it complains: error: ‘_Atomic’ does not name a type. However, clang main.cc -lstdc++ works like a charm.
I'm wondering what makes the difference, and how can I compile it with gcc?

To wrap C headers that use atomics, you may use the other spelling of _Atomic and define a macro that transforms this to valid C++:
#ifndef __cplusplus
# include <stdatomic.h>
#else
# include <atomic>
# define _Atomic(X) std::atomic< X >
#endif
int foo(_Atomic(unsigned)* toto);
Both atomics interfaces have been developed in sync between the two committees, so besides syntax problems these should be binary compatible on any reasonable platform that provides C and C++.

Related

Is there a way to detect if a given header of the C++ Standard Library is included?

More specifically, is it possible to detect, at compilation time, if a C++ standard header file is included (let say <complex>), and do that in a way that is cross-plateform and cross-compiler ? I'd like it to work with C++11 at least, but for the question's sake, is it possible for any C++ standard ?
I know the implementation of the C++ Standard Library is dependent on the compiler and operating system, but is there a standardized guard name for the header, a macro that I can check the existence of ?
I've run into this : Detect usage of STL in C++ , which is a hack not to use the headers, and this : Is there a way to detect portably that a standard header is included using macros?, which answers with a C++17 feature, and is in fact more about detecting a function.
What I want is to be able to write some preprocessor instruction at a given point in the code that will tell whether the header is included (yet). I checked the source code of (an implementation of) <complex> as an example, and _GLIBCXX_COMPLEX is defined, but probably only for this implementation.
TL;DR : No, there is not, apart from the C++17 feature #if __has_include(<complex>). Not with defined macro anyway.
Long answer : there are two parts to the answer. What I read from some headers, and the tests I ran on differents OS with differents compilers.
Warning : I will write also about C, as some compilers uses the same macros. I also use the shortcut 'for C' and 'for C++' instead of 'when the header complex.h is included' and 'when the header <complex> is included'.
Ok, here's my best answer as for now.
About C and complex.h :
In C, the existence of the macro
_Complex_I is the only macro that I think should be defined in any complex.h header, as it is specified by the ISO C99 (cf. ISO/IEC 9899:1999/TC3 text). The tests I ran shows that this is a realistic hypothesis. There are some additionnal macro used, such as _COMPLEX_H that seems to be defined when compiling with GCC,
and _C_COMPLEX_T when compiling with MSVC. There might be others, I didn't find them, please don't hesitate to add them.
But it is C, not C++, and one should not mix both.
About C++ and <complex> :
The C++ standard (ISO/CEI 14882:2011) does not specify such macro. In fact, it does not specify the inclusion of any macro (at first glance).
It does specify the existence of the complex class however, but this does not answer the question.
For what I read, _COMPLEX_ and _C_COMPLEX_T seems to be defined in the <complex> header for
LLVM-clang and MSVC, but also in the complex.h for the apple implementation of the C math library (libm).
However, my tests with the LLVM-clang compiler on macOS failed showing those macro, and I can't find the file where I read that information.
I also found that g++ is defining _GLIBCXX_COMPLEX.
If one wanted to do that with a C++ older than C++17, a solution would be to test with the given compilers and architectures the code will run onto.
That is quite bad, but it's the closest answer I get.
The tests :
I give here the code that I run on the different OS, the compiler options, their version, and the results they prompt. _Complex_I was indeed defined for all C headers.
I wasn't able to run the test on macOS with GCC and G++, but I bet that _Complex_I will be defined with GCC and _GLIBCXX_COMPLEX with G++.
Tests for C++
G++ -std=c++11 v9.3.0 on Ubuntu 20.04 :
_GLIBCXX_COMPLEX
G++ -std=c++11 v11.2.0 on windows 10 (via Cygwin) :
_GLIBCXX_COMPLEX
MSVC default c++11 option v14.29.xxxxx.x on windows 10 :
_C_COMPLEX_T
_COMPLEX_
Apple LLVM-clang -std=c++11 v10.0.1 : None (doesn't mean there is none, just that I don't know which one)
Code for C++:
#include <iostream>
#include <complex>
int main(){
#ifdef _COMPLEX_
std::cout << "_COMPLEX_" << std::endl;
#endif
#ifdef _C_COMPLEX_T
std::cout << "_C_COMPLEX_T" << std::endl;
#endif
#ifdef _COMPLEX_H
std::cout << "_COMPLEX_H" << std::endl;
#endif
#ifdef _Complex_I
std::cout << "_Complex_I" << std::endl;
#endif
#ifdef _GLIBCXX_COMPLEX
std::cout << "_GLIBCXX_COMPLEX" << std::endl;
#endif
return 0;
}
Tests for C :
GCC -std=c99 v9.3.0 on Ubuntu 20.04 :
_Complex_I _COMPLEX_H
GCC -std=c99 v11.2.0 on windows 10 (via Cygwin) :
_Complex_I _COMPLEX_H
MSVC -std=c99 v14.29.xxxxx.x on windows 10 :
_Complex_I _C_COMPLEX_T
Apple LLVM-clang -std=c99 v10.0.1 : _Complex_I
Code for C:
#include <stdlib.h>
#include <stdio.h>
#include <complex.h>
int main(){
#ifdef _COMPLEX_
printf("_COMPLEX_\n");
#endif
#ifdef _C_COMPLEX_T
printf("_C_COMPLEX_T\n");
#endif
#ifdef _COMPLEX_H
printf("_COMPLEX_H\n");
#endif
#ifdef _Complex_I
printf("_Complex_I\n");
#endif
#ifdef _GLIBCXX_COMPLEX
printf("_GLIBCXX_COMPLEX\n");
#endif
return 0;
}
To sum up :
MSVC is defining _C_COMPLEX_T whatever C or C++ used, and also _COMPLEX_ for C++. _Complex_I is always defined for C, and G++ seems to define _GLIBCXX_COMPLEX whatever the plateform (test to be done on macOS) for C++.

Chain of C libraries into C++

I have a very trivial problem including a chain of C libraries into a C++ main project. I've experience with C but it's the first time that I'm programming in C++.
The structure of the project is a single folder with inside:
main.cpp
Mylib_1.c
Mylib_1.h
Mylib_2.c
Mylib_2.h
main calls -> Mylib_1.h that calls -> My_lib2.h
//main.cpp
#include "Mylib_1.h"
//Mylib_1.h
#include "Mylib_2.h"
main contains both Mylib_1 and Mylib_2 functions and typedef structs
Mylib_1 uses typedef structs and functions of Mylib_2
Everything inside each Mylib_x.h is wrapped between extern "C", like this:
#ifndef __MYLIB_X_H
#define __MYLIB_X_H
#ifdef __cplusplus
extern "C" {
#endif
mycode
#ifdef __cplusplus
}
#endif
#endif
But when I try to compile it with eclipse kepler on Ubuntu 12.04 x64, I get:
Mylib_1.h error: Mylib_2_type_t does not name a type
main.cpp error: Mylib_2_function1 was not declared in this scope
...
Only the above sections are marked as error in eclipse, the header looks included fine.
Furthermore according to eclipse, the __cplusplus flag is false into Mylib_2.h but true into Mylib_1.h
Thinking of some eclipse error, I've tried to manually build the project via g++ (v4.6.3) but I got the same exact problem when I've tried to link the libraries .o with the main.cpp
Seems stupid but I can't figure out what could it be. Any suggestion?
Thank you
Have you checked that your lines
#ifndef __MYLIB_X_H
#define __MYLIB_X_H
are really different for the two files,
e.g. _MYLIB1_H and _MYLIB2_H?

GCC cross-compiler for VxWorks can't compile C++

I'm trying to port a Linux library to run on VxWorks. I have successfully built binutils and gcc to target i486-wrs-vxworks and I can successfully build a simple C program. However, when I try to compile C++, things break.
I have a simple Hello World program:
#include <string>
#include <iostream>
int main()
{
std::string s = "Hello World";
std::cout << s << std::endl;
return 0;
}
To build it, I call:
i486-wrs-vxworks-gcc -I/home/kyle/vxworks-6.9/target/usr/h -I/home/kyle/vxworks-6.9/target/usr/h/c++ hello.cpp
This always fails with the message:
In file included from /home/kyle/vxworks-6.9/target/usr/h/c++/cerrno:4:0,
from /home/kyle/vxworks-6.9/target/usr/h/c++/xlocnum:4,
from /home/kyle/vxworks-6.9/target/usr/h/c++/ios:4,
from /home/kyle/vxworks-6.9/target/usr/h/c++/ostream:4,
from /home/kyle/vxworks-6.9/target/usr/h/c++/istream:4,
from /home/kyle/vxworks-6.9/target/usr/h/c++/string:4,
from hello.cpp:1:
/usr/local/lib/gcc/i486-wrs-vxworks/4.6.4/../../../../i486-wrs-vxworks/include/yvals.h:4:24: fatal error: yvals.h: No such file or directory
If I go look inside /usr/local/i486-wrs-vxworks/include/yvals.h, this is what I see:
/* yvals.h values header for conforming compilers on various systems */
#if (defined(__cplusplus) && defined(__GNUC__))
/* GCC C++ has it's own yvals.h */
#include_next <yvals.h>
#else /* __cplusplus && __GNUC__ */
#ifndef _YVALS
#define _YVALS
#ifdef _NO_WINDRIVER_MODIFICATIONS
#include <stdarg.h>
#endif
...
It appears that there is another yvals.h that needs to be included, but I can't find it anywhere. Did I just fail at building gcc correctly, or is there a way to fix this?
Which version of VxWorks are you using for this?
I have a fuzzy recollection that when upgrading VxWorks versions in the past there was a syntax error in yvals.h that was I needed to work around and it was fixed in a subsequent version.
Also, you can get the gcc cross compiler pre-built from WindRiver. Just login to windriver.com/support with your licence number and head to "Downloads" for your product version.
I went through a recent cross compiling nightmare myself (not VxWorks related) except that instead of yvals.h, I was having grief with stddef.h. The problem turned out to be that I needed to specify the include paths for the system header files.
Here are the steps it took me to solve my error messages. Feel free to modify as appropriate.
Create a file foo.c
#include <stddef.h> /* The problem header file (yvals.h for you?) */
int main (void) {
return 0;
}
Compile it with your compiler of choice
$(CC) foo.c -E
Note the include paths it uses and set them as your system header file list using the
-isystem <include path>
option.
Hope this helps.

Use of #include <iostream.h>

I am working on an older project that still has the deprecated "#include iostream.h" inclusions. I understand that iostream.h is deprecated and should not be used, but some of the systems that this code has to run/compile on are old solaris machines running CC and do not have iostream available. My question is: how can I make my more modern g++ compiler accept the iostream.h inclusions.
EDIT: The compilier cannot find the iostream.h file so I am assuming that none of the .h versions of the library are available to g++.
The easiest solution is probably to create a local header file called iostream.h which just includes <iostream> and imports the namespace std. Then, in order for the compiler to allow #include <iostream.h> you add the local path to your include file search path. For g++, this works:
g++ -I local_folder [other flags] …
Incidentally, your remark about
… the deprecated "#include iostream.h"
isn’t quite correct: this isn’t deprecated because it has never been legal C++.
I'd take a step back and write another intermediate header you use everywhere instead that does something like:
#if defined(sun) || defined(__sun)
# if defined(__SVR4) || defined(__svr4__)
/* Solaris */
#include <iostream>
# else
/* SunOS */
#include "iostream.h"
# endif
#else
/* Sane, modern system */
#include <iostream>
#endif

XCode 4.5 'tr1/type_traits' file not found

I use the wxwidget library and I have the following problem:
#if defined(HAVE_TYPE_TRAITS)
#include <type_traits>
#elif defined(HAVE_TR1_TYPE_TRAITS)
#ifdef __VISUALC__
#include <type_traits>
#else
#include <tr1/type_traits>
#endif
#endif
here the #include isn't found. I use the Apple LLVM compiler 4.1. (with the c++11 dialect).
If I switch to the LLVM GCC 4.2 compiler I have no error there, but the main problem is that all the c++11 inclusions won't work.
How can I either use the GCC compiler, but with the c++11 standard or make it that the LLVM can find the ?
any help would be really appreciated.
I'm guessing you have "C++ Standard Library" set to "libc++". If this is the case, you want <type_traits>, not <tr1/type_traits>. libc++ gives you a C++11 library, whereas libstdc++ (which is also the default in Xcode 4.5) gives you a C++03 library with tr1 support.
If you want, you can auto-detect which library you're using with:
#include <ciso646> // detect std::lib
#ifdef _LIBCPP_VERSION
// using libc++
#include <type_traits>
#else
// using libstdc++
#include <tr1/type_traits>
#endif
Or in your case perhaps:
#include <ciso646> // detect std::lib
#ifdef _LIBCPP_VERSION
// using libc++
#define HAVE_TYPE_TRAITS
#else
// using libstdc++
#define HAVE_TR1_TYPE_TRAITS
#endif
This is the command I used to build wxWidgets against libc++ (LLVM C++ Standard Library). Should work on Yosemite and later (at least until Apple breaks everything again):
mkdir build-cocoa-debug
cd build-cocoa-debug
../configure --enable-debug --with-macosx-version-min=10.10
make -j8 #This allows make to use 8 parallel jobs
Slightly modified the code above, to avoid compiler complaints:
Paste the following into strvararg.h just before #ifdefined (HAVE_TYPE_TRAITS)
#include <ciso646> // detect std::lib
#ifdef _LIBCPP_VERSION
// using libc++
#ifndef HAVE_TYPE_TRAITS
#define HAVE_TYPE_TRAITS 1
#endif
#else
// using libstdc++
#ifndef HAVE_TR1_TYPE_TRAITS
#define HAVE_TR1_TYPE_TRAITS 1
#endif
#endif