C vs C++ compilation incompatibility - does not name a type
C++CGccG++C++ Problem Overview
I am trying to use a supplier's library in combination with my C++ application. The library is largely based on C, which is normally not a problem with the extern "C"
option, but I ran into an issue that the C++ compiler does not accept.
I simplified my code into the following example files. header.h represents a header from the suppier library, main.c/cpp are my own files. My real application is a C++ application, so I want to get it to work with main.cpp.
header.h (note the line u64 u64;
):
#ifndef HEADER_H
#define HEADER_H
#include <stdint.h>
typedef uint64_t u64;
union teststruct {
u64 u64;
struct {
u64 x:32;
u64 y:32;
} s;
};
#endif
main.c:
#include <stdio.h>
#include "header.h"
int main() {
union teststruct a;
a.u64=5;
printf("%x\n", a.u64);
return 0;
}
main.cpp (same as main.c but with an extra extern "C"
statement):
#include <stdio.h>
extern "C" {
#include "header.h"
}
int main() {
union teststruct a;
a.u64=5;
printf("%x\n", a.u64);
return 0;
}
Compiling main.c using the line
gcc -o test main.c
compiles without problems. However, compiling the C++ version using the g++ compiler with the command
g++ -o test main.cpp
gives the following compiler errors:
In file included from main.cpp:12:0:
header.h:11:9: error: ‘u64’ does not name a type
u64 x:32;
^
header.h:12:9: error: ‘u64’ does not name a type
u64 y:32;
^
The issue is that the supplier used the same name (u64) for both the type and the variable name, which seems like a bad idea to begin with, but gcc apparently accepts it. I do not want to change the library (i.e. header.h) as it is very large,this occurs a lot in the code, and I occasionally get updates for it. Is there a way to make g++ accept this combination, or a way to modify main.cpp to make it compile without changing header.h?
C++ Solutions
Solution 1 - C++
teststruct
defines a scope in C++. You can form the qualified id teststruct::u64
. So the language rules for name lookup account for that, allowing members of classes and unions to hide identifiers in outer scope. Once u64 u64;
is introduced, the unqualified u64
cannot refer to the global ::u64
, only the member. And the member is not a type.
In C union teststruct
does not define a scope. The field can only be used in member access, so there can never arise a conflict. As such the field need not hide the file scope type identifier.
There is nothing, as far as I can tell, that you may do in order to easily work around it. This library (which is a perfectly valid C library), is not a valid C++ library. No different than if it used new
or try
as variable names. It needs to be adapted.
Solution 2 - C++
It seems that you have a header file that is illegal in C++, so you cannot #include
it in code compiled as C++. If you cannot effect a change in the library header file (e.g. by complaining to your library supplier) then the most straightforward option is to write a thin C++-compatible wrapper around the library:
To isolate your C++ code against the C header, create a Wrapper.h
and Wrapper.c
, where the .h
is valid for inclusion in C++, does not include header.h
, and provides all types and functions that you need for library interaction. Then, in the .c
, you can #include "header.h"
and implement all the calls (and whatever you need to do to safely convert between the types). This would obviously have to be compiled as C, not C++.
Solution 3 - C++
If your mentioned incompatibility between C and C++ is the only one, you should be able to convert header.h
to C++ compatible header file programmatically, name it something like header.hpp
. And then you can convert newer versions the same way.
Compiler errors tell you everything about what and where should be changed:
header.h:11:9: error: ‘u64’ does not name a type
- Open
header.h
; - Seek position 11:9;
- Insert
::
there; - Repeat for all
does not name a type
error.
Some string processing and it's done.
PS: C to C++ converters may able to do that too.