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
  1. Open header.h;
  2. Seek position 11:9;
  3. Insert :: there;
  4. 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSanderView Question on Stackoverflow
Solution 1 - C++StoryTeller - Unslander MonicaView Answer on Stackoverflow
Solution 2 - C++Max LanghofView Answer on Stackoverflow
Solution 3 - C++Andrew SvietlichnyyView Answer on Stackoverflow