I have some header file that was written for use in a C99 program. This header includes all the function definitions, and is not paired with a source file. I am including it in a C++ file.
My C++ compiler flags include -pedantic -std=c++11, which gives me various warnings in the header file such as "ISO C++ forbids compound literals", and "ISO C++ forbids variable length arrays". Obviously the C++ compiler is treating the C99 code as C++. Two questions:
Is this a potential problem when trying to write code that will run correctly on various platforms using different compilers?
What is a good way to resolve the warnings, and produce standard conforming code? I was thinking of making a precompiled header file using gcc, but don't know enough about the process to be assured that I am not going to have unintended consequences from included a C precompiled header in a C++ source.
Thanks
Is this a potential problem when trying to write code that will run correctly on various platforms using different compilers?
Yes. GCC may just give a warning, other compilers (e.g. Visual Studio, or GCC with other options) could very well give an error.
What is a good way to resolve the warnings, and produce standard conforming code?
The correct way to resolve the problems is to write the header in the common subset of C and C++. Functions and object-definitions that use C99 features (such as variable-length arrays and compound literals) should be moved to a separate C source file (that gets compiled with a C compiler!).
To include a pure C header file(*) in a C++ project, you should wrap the include statement in an extern "C" block:
// C++
extern "C" {
// C-code goes here
#include "foo.h"
}
This is because C++ performs name mangling on all function names to make overloading work. C doesn't use name mangling, so C++ parses C function signatures with name mangling.
Please note that extern "C" doesn't put the compiler into "C-mode" (there is no such mode but you might falsely think of this instruction as such), it doesn't mangle the function names (+ changes the calling convention and forbids overloading; thanks for doomster for pointing these things out).
However, it shouldn't be a problem if you are including a header only (with inline implementations), since this name mangling will only be a problem when you link the C source file or library against your C++ project, since the function names are different in this case.
This being said, you should use the common subset of C and C++ for the header file, extract and compile the implementations of these functions separately with a C compiler, not C++. Then, you (hopefully) can link both parts together. A lot of C libraries already have headers which are compatible with C++, so this is a common procedure.
(*): Some header files are already made to be compatible with both languages C and C++ by using the common subset of language features plus wrapping everything in a conditional extern "C" block. For such headers, you should not use this method, but only for the ones which don't have such a block in it.
Related
I'm a little new to C++ and I have a question regarding converting C code into C++ code, as well as mixing C and C++ code.
For example, I'm refactoring a previous C file to a C++ file because I am now required to use a std::string in the header file's struct. It now looks as follows (firstClass.hpp):
struct firstClass
{
.
.
.
std::string test_string;
firstClass();
firstClass(const firstClass &c);
~firstClass();
};
And as a result, here's first-class.cpp:
#include "firstClass.hpp"
extern "C"
{
.
.
.
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
}
.
.
.
Now here's my question: I have other files that previously included firstClass.h (Note: this is the C-variant) before I converted it to C++ code -- do these files need to also be converted to C++ code? Also, if additional files include these files mentioned above will they need to be converted as well? I guess to sum up my question: after converting this initial file to C++, how far down the chain of includes do I need to also convert those files?
Most C++ compilers will process both C source code files, files with a .c extension, and C++ source code files, files with a .cpp extension. So the first step in a conversion would be to change to a C++ compiler and get your project files and/or make files in order so that it all compiles.
The next thing is to go through the source code base to determine what data structures are going to change and which include files, normally files with a .h extension, have these data structures that will need to change.
At this point you will need to begin partitioning out what source is C++ and what source is C. For instance while C struct is a subset of the C++ struct, C++ struct allows for constructors and deconstructors which C does not allow. This means you can use a C struct with C++ source but you can not use a C++ struct with the C++ features in a C source file.
Other C++ language keywords such as class just won't work period with a C source code file.
Next is to look at what C++ features, such as templates and C++ Standard Library functionality such as std::string, you are going to use. Again you will need to partition off the C++ source from the C.
The extern "C" functionality allows you to use C functions with C++ source code by declaring a function or variable name as being C rather than C++. This is necessary because the C++ compiler does name mangling, using an algorithm to generate a modified name for functions allowing function overloading. See What is name mangling, and how does it work?
The other thing you will be faced with is that C++ has introduced new versions of most of the standard C include files without the .h extension. You can use the old version with C++ but the new versions are preferred since they are for C++. However C source files can only use the old, .h extension, version of these files.
Conditional compilation for header files
The magic that allows the use of the older standard C include files with C++ source code is that most compilers have a special #define which can be used to do conditional compilation. With the Visual Studio compiler the special define is __cplusplus and it can be used something like:
#if defined(__cplusplus)
extern "C" {
#endif
// The type CONNENGINEHANDLE is for future expansion to allow multiple
// sockets to be managed by the dll.
typedef unsigned short CONNENGINEHANDLE;
// following functions are used with a server implementation.
// these functions will setup the parameters for the server and
// start the listen needed to accept a connection from a client
CONNENGINE_API int fnConnEngineSetDomainNamePort(CONNENGINEHANDLE hConnEngineSocket, char *aszDomainName, int nPortNo);
CONNENGINE_API int fnConnEngineStartEngine (int nPort, HWND hWinHandle, UINT wReceiveMsgId);
CONNENGINE_API int fnConnEngineStopEngine ();
#if defined(__cplusplus)
};
#endif
What the above preprocessor code that is part of an include file does is to allow a C++ source code file to include the same header file as C source code files but when it is included in the C++ file, the extern "C" { is part of the header file text because the Preprocessor has the __cplusplus defined. So the C++ source is able to use functions defined in the C source code and the name mangling ordinarily done with C++ is turned off for those functions whose declarations are within the braces.
However though this special #define to detect if a C++ source file is being processed by the Preprocessor you still can't use C++ language constructs in C source files. You will still need to partition out the C++ from the C.
Interface functions for C calling C++ functionality
In some cases you may need to execute C++ source code functionality from C source code functionality. In those cases you will need to create a C compatible interface to the C++ functionality.
For instance if you have a struct that contains a std::string, which is incompatible with C source code, you can create the C++ source code to hide the implementation details and to then provide a C compatible interface.
For instance from the include file example showing the use of __cplusplus above, one of those functions is defined in a C++ source code file as follows. This C++ source code file also include the same header file as would be used with a C source code file and with the declaration above for the function fnConnEngineStartEngine(), the C++ compiler knows it is not supposed to name mangle the function name fnConnEngineStartEngine{}. This C++ source code provides an interface between C source that uses the C++ object theApp.
CONNENGINE_API int fnConnEngineStartEngine (int nPort, HWND hWinHandle, UINT wReceiveMsgId)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (hWinHandle == 0)
hWinHandle = theApp.m_hWinHandle;
if (wReceiveMsgId == 0)
wReceiveMsgId = theApp.m_wReceiveMsgId;
theApp.StartEngineAsServer (nPort, hWinHandle, wReceiveMsgId);
return 0;
}
What you want to do is use a C++ compiler on the C code. The C++ compiler will process the C code just fine and handle the C++ syntax.
Not sure what compiler or IDE you're using. This can be done for many compilers by adding an argument on the command line or to build options. Or by an option in the compiler settings for an IDE.
I have an third party source file and corresponding header (containing the declarations and include directives for GSL etc) which are written in C. I am trying to build an R package around these source files, basically making a wrappers for the functions using Rcpp. Problem is that these files contain restrict qualifier which is not part of the C++ standard, so R CMD INSTALL cannot compile the package. It does use C compiler for .c file, but want's to compile .h file with C++ compiler and it fails. it fails when it finds restrict in header file (which is included in .cpp file).
I am not that familiar with C and compiler things and Rcpp etc, so I am not sure what would be a best approach here?
Easiest thing would probably be to remove the restrict keyword. This is what I have currently done (I am suprised that R CMD INSTALL works when I remove restrict from header file but leave them to .c file). But I rather not alter the .c and .h files as they are also used in non-R environment by others (executable and in Python) and it would be nice to have identical files for all projects.
I also tried to define empty keyword restrict so that it would just "remove" restrict from function definitions if the compilation was done in C++ compiler, but I couldn't get that work. I read about similar approach somewhere but apparently it doesn't work that way.
Would it work if I could somehow tell the compiler (via Makevars or something?) that the particular .h file should be compiled with C compiler? Or is there going to be problems with C++ function calling those functions?
Or will the whole keyword even matter in terms of performance if those functions are called from R via C++ wrapper?
One thing would be to just ditch the Rcpp and use .C instead of .Call from R, but as the performance is a key here, that doesn't feel a good option, as I understand that .Call is faster (and more reliable).
Note that eventually this package could find it's way to CRAN, so the solution should be fairly portable. There seems to be some C++ compiler specific keywords for restrict but I guess those are not an option due to the portability.
It sounds like you are making a .cpp file which does #include <x.h> where x.h is a C header which uses restrict. If that's true, I think you can modify your .cpp file to do this:
#define restrict // nothing
extern "C"
{
#include <x.h>
}
Then compilation of your C++ code will not see the restrict keyword, and also I have wrapped the header in extern "C" because if the header itself doesn't do that internally, you need to, in order that your C++ compiler will not apply C++ "name mangling" to the functions declared inside.
I have a C++ file that compiles fine in one project, but not in another. The file is the exact same C++ file in both projects.
Both projects are MFC dialog-based projects. They have slightly different stdafx.h files... but if I'm prepared to break the rest of the project, I can make them identical... and still get this compiler error. Equally, they have considerably different include paths, but if I break even more of the project and make the include paths identical, I still get the error. It goes without saying that I have made all my preprocessor directives identical... and I still get the error.
So, as far as I can tell, I'm down to compiler switches. I've made them identical (within reason - I haven't bothered to change the /Fp, /Fd or /Fo output files), but still it refuses to compile. Are there any "hidden" settings or anything else that might be affecting compilation?
[Note: the following is included mostly for historical reasons - it led to an unintentional over-emphasis when this question was originally posed, and so led to predictable comments and answers which didn't help resolve the intended "when is identical not identical?" question]
The error itself is error 2894 (templates cannot have 'C' linkage). I understand this error, but not how/why it is occurring. It occurs within a bunch of C header files pertaining to a C library. They are all neatly wrapped in extern "C" {...} declarations, with #ifdef __cplusplus correctly applied. But extern C {...} is not something I'm very familiar with, so... is there anything special about extern "C" {...} that might be a factor?
If a single C++ file is compiled under the same conditions, it leads to the same result. It doesn't matter if it is in a project with zero other files, or a hundred other files - the compiler compiles each file individually.
Therefore, if a single C++ file compiles with different results, then that is either because:
It is not really the same single C++ file, or
It is not really the same compilation conditions.
You can see exactly what the Microsoft Visual C++ compiler thinks your "single" C++ file truly is by specifying /showIncludes as an "advanced" compiler option. You might be surprised to see how different your "identical" C++ file is (and this was the case here).
Equally, you can see the explicit C++ compiler conditions listed under the Command Line summary that appears at the bottom of the list of C/C++ options in the project properties in Visual Studio.
wspapi.h includes some C++ template code outside of its internal extern "C" section. If you were to externally wrap the header in an extern "C" declaration, you would break it.
For example, you cannot do this:
extern "C"
{
#include <wspapi.h>
}
Similarly, if a preceding header or code has failed to terminate an extern "C" block so that all the content of the header is given C linkage, the same situation arises.
Put simply, wpsapi.h has been included within a C linkage block, it has nothing to do with "hidden options".
If I use gcc as a driver, call all my source files .c and .h, can I be sure that I wont have any C++ source in my sources? Are there any gcc parameters to make sure that he throws errors in case any c++ is encountered in the source?
I am especially paranoid about include files, because I am not 100% sure whether I include C headers or C++ headers.
Some examples I ran into in the past:
trying to use the type bool
using wrong includes cstdio vs. stdio.h
trouble with the struct keyword
I just want to make 100% sure that my source is only C and has no C++ in it.
GCC will figure out itself whether it's a C or a C++ source code. How? It scans the file extension the file you passed has.
These are the extensions accepted.
In case you want to force a specific language, use the -x flag (documented in the link above). Furthermore, you may check whether the macro __cplusplus is defined.
I am relatively new to Mixed C/C++ applications using the gcc and g++ tools.
To get the hand of it I have downloaded the iperf source code and built it with success using Eclipse.
There is one oddity: If I look into the file "Thread.c" using Eclipse it thinks there is a syntax error and underlines almost the whole file as if the code is flawed, which it is absolutely not.
This is the piece of code that triggers it:
#ifdef __cplusplus
extern "C"
{
#endif
I know what extern "C" is used for in C++ but Eclipse has problems with it when present in .c files. It happily accepts it in .cpp and .h files though.
I have checked out how the Make utility builds the iperf application and I see it always uses gcc to compile c files and g++ to compile cpp files which makes me wonder if extern "C" is actually required. It most definitely does not hurt because the gcc compiler happily deals with it but if it is not strictly required I could omit it and get better readability in Eclipse.
I have also looked at a possible solution for Eclipse's behaviour but have not really found one, if anybody can point out how to solve it that would be equally good.
If you are using Eclipse, what you seeing in editor has to do with Eclipse internal indexer/parser. Your mixed C/C++ project may compile and build with no issues, but when you open a source file which has
#ifdef __cplusplus
extern "C" {
#endif
you may see a syntax error marked on the extern "C" line. This means that "__cplusplus" symbol is defined for your C compiler in your project settings.
In order to get rid of that syntax error in the Eclipse editor, go to project Properties -> C/C++ General -> Paths and Symbols -> # Symbols tab, and select "GNU C" (or whatever C compiler you use) under "Languages" column. Scroll through Symbol/Value list on the right, find the "__cplusplus" symbol and delete it. Make sure you do that only for C compiler.
Click OK to close the project Properties window and the syntax error warning will be gone in Eclipse editor.
that piece of code is normally found in headers, and should be always be written to header files that belong to c-files. (with the corresponding closing bracket at the end of the header)
reason is, that c uses a different scheme how the functions are internally called (--> name mangeling). while the compiler can distinguish a c++ code file from c code file by its extension it can not distinguish between a c-header and a c++ header that is included from a cpp file. so it does not know if it has to mangle the name of the declared functions or not (by default it does).
then the linker tries to match the used symbols (reference to function from cpp) with the created one (defined by the c-file) it does not find the symbol if the compiler was not told not to mangle the declaration.
extern "C" is only legal in C++ and ensures that the specified function(s) have C linkage. This means that the function parameters are not mangled into the binary function name.
To ensure that the header file compiles in C we include the #ifdef __cplusplus __cplusplus is defined by a C++ compiler and not a C compiler. This use used to protect C code from the C++ only extern "C" directive.
IDE's so not use compilers for code intelligence and therefore may get things wrong.
probably just a silly workaround for your issue.
what i found is that, while using c functions in cpp file, theoretically extern is required.
But i found that in eclipse oxygen version, we do not have to specify extern c, we can directly use c functions and printf statements too in cpp file and it just works fine.
Havent tried in older versions of eclipse.
My solution may not be very helpful, but you could give it a try. It worked for me.