1

I'm working on migrating a large project from VS2012 to VS2015 (baby steps, I know), and I'm running into an issue with C headers no longer compiling, erroring out on reserved c++ keywords - even though they're being included with extern C.

Here's a simplified example (Compiles in 2012, but not 2015)

main.cpp

extern "C" {
    #include "cheader.h"
}

int main()
{
    printfFromC();
    return 0;
}

cheader.h

#ifndef HEADER_H
#define HEADER_H

extern int export;
int printfFromC();

#endif

ctest.c

#include "cheader.h"
#include <stdio.h>

int export = 0;

int printfFromC()
{
    export++;
    return printf("Hello from C (invocation %d) !\n", export);
}

with the following errors:

------ Build started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
  main.cpp
c:\[...]\cheader.h(4): warning C4091: 'extern ': ignored on left of 'int' when no variable is declared
c:\[...]\cheader.h(4): error C2143: syntax error: missing ';' before 'export'
c:\[...]\cheader.h(4): error C3378: a declaration can be exported only from a module interface unit

Edit:

I made a mistake in creating the example - the keyword that's the cause of the trouble is export - not any c++ reserved keyword as I first thought. The example below has been modified to use int export instead of int new

Tyzoid
  • 1,072
  • 13
  • 31
  • @NathanOliver I made a mistake in creating the example - the keyword that's the cause of the trouble is `export` - not any c++ reserved keyword as I first thought. – Tyzoid Nov 05 '18 at 17:13
  • `export` is also a reserved word in C++ –  Nov 05 '18 at 17:15
  • @NeilButterworth Yes - but the difference is this example compiles in 2012 now. – Tyzoid Nov 05 '18 at 17:16
  • Because your ancient compiler did not support the C++11 Standard properly. –  Nov 05 '18 at 17:18
  • See: https://stackoverflow.com/questions/36867325/how-to-link-old-c-code-with-reserved-keywords-in-it-with-c?noredirect=1&lq=1 – Tyzoid Nov 05 '18 at 17:40

3 Answers3

6

The use of extern "C" controls name-mangling of the code it is applied to - it doesn't magically make the compiler compile that code as C. So when you #include the header containing extern int export; in main.cpp, it is compiled as C++ code, and as export is a reserved word in C++, you get a syntax error.

  • This doesn't explain why it compiles in VS2012 though - the app I'm migrating references a C library header that has these keywords. – Tyzoid Nov 05 '18 at 17:18
  • It compiles because VS2012 did not support the C++11 Standard correctly. –  Nov 05 '18 at 17:19
3

new is a keyword in C++. You can't use it as an identifier in cross-compiled code. This is the reason for the error. You'll have to come up with a different name for the variable.

Note that placing a portion of a C++ translation unit into extern "C" { ... } region does not mean that the code will somehow be compiled as C code. It simply means that external entities in that region will receive C linkage. The code itself is still compiled as C++ code and all C++-specific restrictions still apply.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
-1

Digging further, the hack suggested here seems to work: https://stackoverflow.com/a/36869181/1486100

Changing main.cpp in the following way allows it to compile.

extern "C" {
    #include "cheader.h"
}

int main()
{
    printfFromC();
    return 0;
}

to

extern "C" {
    #define export extern_export
    #include "cheader.h"
    #undef export
}

int main()
{
    printfFromC();
    return 0;
}
Tyzoid
  • 1,072
  • 13
  • 31
  • 1
    Yes, unsurprisingly changing the name `export` to something else will fix the problem. But only if the original name is never used anywhere, in which case why not remove it altogether? –  Nov 05 '18 at 17:51
  • 1
    No, it does not work, since it only affects the external declaration but does not affect the variable definition. Now your `extern_export` variable is undefined. – AnT stands with Russia Nov 05 '18 at 17:58
  • @AnT: Not sure what your point is - it's changing the name of the variable names defined by keyword, but doesn't actually affect anything that the c++ application would use, since it can't use those names anyway. This allows it to compile. Anything it's dynamically linked against will still work as expected. – Tyzoid Nov 05 '18 at 18:05
  • @NeilButterworth This is a simplified example - I'm trying to work around a vendor library we can't change. – Tyzoid Nov 05 '18 at 18:05
  • 2
    @Tyzoid My point is that if you try using this variable in your C++ code under its new name, you will end up with linker errors, since the variable is not defined. Apparently, you don't care to use this variable on the C++ side and just want the header to compile - this is the important detail you forgot to mention. – AnT stands with Russia Nov 05 '18 at 18:10
  • @AnT I might be missing something, but I wouldn't think this to be an issue, given that the variable name before was a reserved keyword, so I would not expect to use it anywhere in my c++ program. You do raise a good point for future readers, though. – Tyzoid Nov 05 '18 at 18:17
  • @Tyzoid But the point is that you _could_ have used it when your C++ code was compiled with VS2012 because the compiler would not recognise the keywords. Anyway, you will find out when you try to link your code. –  Nov 05 '18 at 18:34