I just read a question on SO discussing scenarios in which a piece of code is valid in both C and C++ but would produce different behavior in each language.
This begs the question: Could this ever be a problem when including C headers in C++ code?
I know from this question that you should include C headers like this:
extern "C" {
#include <your_os_or_library_header_in_c.h>
}
But all I found so far is that the extern "C" only guarantees that name mangling is turned off.
I couldn't find any information on whether it evaluates all statements as C, so that e.g. sizeof('a') or 10 //* comment */ 2 (which you could find in an inline function) are parsed as C and not C++. (Note that relying on such behavior as someone who writes a C header is obviously a bad idea, but I'm asking it from a purely academic standpoint of "What if?".)
Does the C++ standard say that enclosing a block of code in extern "C" means that all statements in it must be parsed as C?
extern "C" is a C++ construct which affects language linkage in a C++ program. It does not switch the language to C in any way. All source text inside an extern "C" declaration is still parsed as C++ and as C++ only.
Note that extern "C" affects more than just name mangling - it is (theoretically) possible that functions with C and C++ language linkage could have different calling conventions, for example.
extern "C" only changes linking, i.e. mangling and possibly the calling convention. Try compiling and running this program with both a C and a C++ compiler:
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
inline void putsizeofchar()
{
printf("%zd\n", sizeof(char));
}
#ifdef __cplusplus
}
#endif
int main()
{
putsizeofchar();
return 0;
}
Since header inclusion is textual substitution in both languages, the lack of a header doesn't make any difference.
Related
My C++ program needs to use an external C library.
Therefore, I'm using the
extern "C"
{
#include <library_header.h>
}
syntax for every module I need to use.
It worked fine until now.
A module is using the this name for some variables in one of its header file.
The C library itself is compiling fine because, from what I know, this has never been a keyword in C.
But despite my usage of the extern "C" syntax,
I'm getting errors from my C++ program when I include that header file.
If I rename every this in that C library header file with something like _this,
everything seems to work fine.
The question is:
Shouldn't the extern "C" syntax be enough for backward compatibility,
at least at syntax level, for an header file?
Is this an issue with the compiler?
Shouldn't the extern "C" syntax be enough for backward compatibility, at least at syntax level, for an header file? Is this an issue with the compiler?
No. Extern "C" is for linking - specifically the policy used for generated symbol names ("name mangling") and the calling convention (what assembly will be generated to call an API and stack parameter values) - not compilation.
The problem you have is not limited to the this keyword. In our current code base, we are porting some code to C++ and we have constructs like these:
struct Something {
char *value;
char class[20]; // <-- bad bad code!
};
This works fine in C code, but (like you) we are forced to rename to be able to compile as C++.
Strangely enough, many compilers don't forcibly disallow keyword redefinition through the preprocessor:
#include <iostream>
// temporary redefinition to compile code abusing the "this" keyword
#define cppThis this
#define this thisFunction
int this() {
return 1020;
}
int that() {
return this();
}
// put the C++ definition back so you can use it
#undef this
#define this cppThis
struct DumpThat {
int dump() {
std::cout << that();
}
DumpThat() {
this->dump();
}
};
int main ()
{
DumpThat dt;
}
So if you're up against a wall, that could let you compile a file written to C assumptions that you cannot change.
It will not--however--allow you to get a linker name of "this". There might be linkers that let you do some kind of remapping of names to help avoid collisions. A side-effect of that might be they allow you to say thisFunction -> this, and not have a problem with the right hand side of the mapping being a keyword.
In any case...the better answer if you can change it is...change it!
If extern "C" allowed you to use C++ keywords as symbols, the compiler would have to resolve them somehow outside of the extern "C" sections. For example:
extern "C" {
int * this; //global variable
typedef int class;
}
int MyClass::MyFunction() { return *this; } //what does this mean?
//MyClass could have a cast operator
class MyOtherClass; //forward declaration or a typedef'ed int?
Could you be more explicit about "using the this name for some variables in one of its header files"?
Is it really a variable or is it a parameter in a function prototype?
If it is the latter, you don't have a real problem because C (and C++) prototypes identify parameters by position (and type) and the names are optional. You could have a different version of the prototype, eg:
#ifdef __cplusplus
extern "C" {
void aFunc(int);
}
#else
void aFunc(int this);
#endif
Remember there is nothing magic about header files - they just provide code which is lexically included in at the point of #include - as if you copied and pasted them in.
So you can have your own copy of a library header which does tricks like the above, just becoming a maintenance issue to ensure you track what happens in the original header. If this was likely to become an issue, add a script as a build step which runs a diff against the original and ensures the only point of difference is your workaround code.
When I build source, it throws an error: declaration of 'globalMemTrace' has a different language linkage
#ifdef MEMDEBUG_SIMULATIONS
#include "mem-trace.h"
MemTrace *globalMemTrace;
#endif
// omitted unrelated parts
int Tcl_AppInit(Tcl_Interp *interp)
{
#ifdef MEMDEBUG_SIMULATIONS
extern MemTrace *globalMemTrace;
globalMemTrace = new MemTrace;
#endif
}
I've googled several times for it. Some said that it is due to a bug if clang and some said tricks in using extern differently may solve it.
But since I am not such a profession, I've tried some of them and failed to solve it. Is there any nice way to deal with it?
It's written in C++ and the problem occurs at extern MemTrace *globalMemTrace;
C++ offers linkage between C++ and non-C++ languages in the from of language linkage.
For example
// in C++ program
extern "C" int displayfoo(const char *);
int main() {
return displayfoo("hello");
}
/* in C program */
#include <stdio.h>
extern int displayfoo(const char * str) {
while (*str) {
putchar(*str);
putchar(' ');
++str;
}
putchar('\n');
}
You are using a C function displayfoo from c++ code, So you need to tell the compiler/linker that it is from different language. That is done by extern "C".
In your code MemTrace *globalMemTrace; may be declared previously in a C code or a C block inside c++, So you need to declare it like
extern "C" MemTrace *globalMemTrace;
It means that the actual variable was declared in C code, or at least wrapped in an extern "C" block in C++ code, but the extern is declared in C++ code, thus it cannot link to the variable as they exist in different languages.
Have a look at these articles:
Language linkage
Linking C and C++ code
It seems that this name is already declared as having C language linkage.
extern "C" MemTrace *globalMemTrace;
I have a mix of C C++ code. All compiled with g++. Wherever I have C headers I have the contents of the header file included inside
#if defined(__cplusplus)
extern "C" {
#endif
and
#if defined(__cplusplus)
extern "C" {
#endif
But in one C header file I get g++ compilation errors where I have accidentally used a parameter name as template , which obviously is incorrect and in conflict with c++ keyword template.
I know I can go and change this parameter name, but I am thinking why is this extern "C" declaration not working and why is the header file considered as C++ code and not C as I intended to.
g++ version 4.1.1 Linux Red Hat Enterprise.
The extern "C" only tells the compiler (actually, the linker) that C++ name mangling doesn't apply to the functions declared in that scope. It has nothing to do with the syntax or keywords themselves.
Your best solution is to rename the conflicting symbols.
Consider:
extern "C" {
namespace n
{
int& foo(bool b)
{
if (!b)
throw std::invalid_argument("fail!");
static int i = 0;
return ++i;
}
}
}
This function has C language linkage, but uses references, namespaces and exceptions, which I hope demonstrates that extern "C" doesn't magically switch the compiler to compiling C, it just tells the compiler to use C calling conventions and symbol-naming conventions for the functions and variables with C language linkage (which usually just means it disables name-mangling and causes matching declarations in different namespaces to refer to the same entity.)
When using G++ (e.g. version 4.5 on Linux) can anyone explain what will/can happen if a user writes a header file for a mixed C/C++ system like this:
#ifdef __cplusplus
extern "C" {
int myCPPfunc(some_arg_list....); /* a C++ function */
}
#endif
but here myCPPfunc() is a normal C++ function with a class def inside - i.e. it was wrongly labeled as a C function.
What is the impact of this?
The main impact of this is that you cannot overload it, e.g. this is legal:
int myCPPfunc(int a);
int myCPPfunc(char a);
But this is not:
extern "C"
{
int myCPPfunc(int a);
int myCPPfunc(char a);
}
It is perfectly legitimate to have the implementation of an extern "C" function use arbitrary C++ features. What you can't do is have its interface be something you couldn't do in C, e.g. argument overloading, methods (virtual or otherwise), templates, etc.
Be aware that a lot of the "something you couldn't do in C" cases provoke undefined behavior rather than prompt compile errors.
This tells the C++ compiler that the functions declared in the header file are C functions.
http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.2
This is exactly what extern "C" is for - it allows you to write a C++ function that can be called from C.
Essentially, that declaration is telling the C++ compiler that you want the C++ function myCPPfunc() to have an external interface that is linkable (and therefore callable) from C.
The implementation of the function is still C++ and can still use C++ features.
Typically, the declaration of the function in the header file might look more like:
#ifdef __cplusplus
extern "C" {
#endif
int myCPPfunc(some_arg_list....); /* a C++ function */
#ifdef __cplusplus
}
#endif
That lets the same header file be used by either the C++ compiler or the C compiler, and each will see it as declaring a C callable function.
I want to use some c++ classes in shared library with C linkage. And i got following problems.
If
#include <iostream>
extern "C"
{
void f(){}
}
Compiles and links succesfully, but f() could not be found in resulting library.
If
extern "C"
{
#include <iostream>
void f(){}
}
I got many compiler errors (just dont know how to correctly translate them in english, something about template with C linkage) on every occurence of C++ keyword "template" in iostream and included headers.
What should be done?
The first variant is correct. Only stuff that even exists in C can be declared in a extern "C" block, and templates and classes certainly don't belong in that category. You only have to make sure, that your function is also declared as extern "C" in the header if you are using a C++-compiler. This is often achieved by writing
#ifdef __cplusplus
// C++ declarations (for example classes or functions that have C++ objects
// as parameters)
extern "C"
{
#endif
// C declarations (for example your function f)
#ifdef __cplusplus
}
#endif
in the header.
The first is correct; system headers (and most other headers as well)
can only be included at global scope, outside any namespaces, classes,
functions or linkage specification blocks. There are likely things in
<iostream> that wouldn't be legal in an extern "C", and even if
there weren't, the name mangling for extern "C" is almost certainly
different from that of C++, and the library itself was surely compiled
as extern "C++".
How did you define f? This could be a similar problem: if the source
file compiles it as an extern "C++" function, then the name will be
mangled differently than it was in the client files which compiled it as
an extern "C" function.
The general policy here is to handle the headers and the function
definitions/declarations in the same way you normally do, except that
you ensure that the header can be included in both C and C++ sources,
e.g.:
#if __cplusplus
extern "C" {
#endif
void f();
// Other `extern "C"` functions...
#if __cplusplus
}
#endif
Then include this header in all files where the function f() is used,
and in the file where it is defined.
Use __declspec to export functions, classes, etc...
Also: http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx
And this one is very good: http://www.flounder.com/ultimateheaderfile.htm