Calling C++ functions from a C src - c++

I have mixed code base of C/C++ in a MS Visual Studio 2010 project and am trying to call a static function defined in C++ file from a C src file. Right now I get it to work by renaming the C src to CPP (a.c -> a.cpp) Just wondering if there's a more graceful way of getting around it (turning some magic compiler flags on etc) without doing any large scale surgery to the code base(like using opaque pointers as suggested in this thread)
Pls note my code base is pretty complex, I have created this small VS snippet to reproduce the error with bare minimum demonstrable code
a.c
#include "b.h"
void test()
{
B::func();
}
b.h
#ifdef __cplusplus
extern "C" {
#endif
class B{
public:
static void func();
};
#ifdef __cplusplus
}
#endif
b.cpp
#include "b.h"
#ifdef __cplusplus
extern "C" {
#endif
void B::func()
{
return;
}
#ifdef __cplusplus
}
#endif
Error:- In MS Visual Studio 2010
1>c:\.....\b.h(5): error C2061: syntax error : identifier 'B'
1>c:\.....\b.h(5): error C2059: syntax error : ';'
1>c:\.....\b.h(5): error C2449: found '{' at file scope (missing function header?)
1>c:\.....\b.h(8): error C2059: syntax error : '}'

First, :: is not valid in C.
Second, including a header is equivalent to copy-pasting a .h file into your C file. Your header must be valid C. Here's some deeper insight:
How to call C++ function from C?
Elegantly call C++ from C
Though, my alternative advice is, compile your C as C++. There's a chance it would take minimal or no work to turn out as valid C++.

Related

Syntax error C2059 when building building C application using C/C++ DLL header

I'm attempting to translate a C++ DLL header file into a C/C++ compatible header. While I've gotten most of the major constructs in, I'm running into one last compiler issue I can't seem to explain. The following code works fine in C++ but when I attempt to compile a C application which just includes this file I get errors for my function definitions in my header file.
Code.h:
typedef void *PVOID;
typedef PVOID HANDLE;
#define WINAPI __stdcall
#ifdef LIB_EXPORTS
#define LIB_API __declspec(dllexport)
#else
#define LIB_API __declspec(dllimport)
#endif
struct ToolState
{
HANDLE DriverHandle;
HANDLE Mutex;
int LockEnabled;
int Type;
};
#ifdef __cplusplus
extern "C" {
#endif
(LIB_API) int SetRate(ToolState *Driver, int rate);
(LIB_API) void EnableLock(ToolState *Driver) ;
(LIB_API) int SendPacket(ToolState *Driver, unsigned char *OutBuffer, int frameSize);
//These also give me the same error:
//LIB_API WINAPI int SendPacket(ToolState *Driver, unsigned char *OutBuffer, int frameSize);
//__declspec(dllimport) WINAPI int SendPacket(ToolState *Driver, unsigned char *OutBuffer, int frameSize);
//Original C++ call that works fine with C++ but has multiple issues in C
//LIB_API int SetRate(ToolState *Driver, int rate);
#ifdef __cplusplus
}
#endif
Errors:
error C2059: syntax error : 'type'
error C2059: syntax error : 'type'
error C2059: syntax error : 'type'
Google searching hasn't generated any relevant results. The following threads were close but don't exactly answer my question:
C2059 syntax error using declspec macro for one function; compiles fine without it
http://support.microsoft.com/kb/117687/en-us
Why is this syntax error occuring?
In C, structs are not types, so you must use struct Foo and enum Bar where in C++ you are able to use Foo and Bar.
Notes:
In C++, you can still use the old syntax even when the type is a class.
In C, people often use typedef struct Foo Foo which allows the same syntax as in C++ then.

Compile as C code in Visual Studio 2010

I am writing some C code to interface with a piece of hardware. This hardware has built-in API functions, which are defined in a header file, enclosed in an extern "C" block. For some reason, I cannot get the program to compile when I select "compile as C code" in the property sheets. Even stranger, I can get it to give no errors when I "compile as C++", don't change any code, then change it back to "compile as C". What is going on? The only two files I have are main.c, header_file.h, and a defines_file.h (which is #included in header_file.h).
I wrote a very simple program to illustrate what is happening:
#include "header_file.h"
int main(){
return 0;
}
To give some more detail, the error I am getting is coming from the header file, which looks something like:
#ifdef __cplusplus
extern "C" {
#endif
#include defines_file.h
FUNC_API(int) Function(Type1 var1, Enum2 var2, Type3 var3, void* ptr=0);
#ifdef __cplusplus
}
#endif
The defines_file.h looks like:
enum Enum2{
//enumerator list
};
The errors are:
1>c:\header_file\include\header_file.h(78): error C2146: syntax error : missing ')' before identifier 'var2'
1>c:\header_file\include\header_file.h(78): error C2081: 'Enum2' : name in formal parameter list illegal
1>c:\header_file\include\header_file.h(78): error C2061: syntax error : identifier 'var2'
1>c:\header_file\include\header_file.h(78): error C2059: syntax error : ';'
1>c:\header_file\include\header_file.h(78): error C2059: syntax error : ','
1>c:\header_file\include\header_file.h(78): error C2059: syntax error : ')'
It seems like it's thinking that Enum2 is a variable name of Type1. It's as though I'm missing the Enum2 definition, but I'm not - it's defined in defines_file.h. One thing I did notice is that Enum2 is not defined inside an "extern C" block. Is that a problem? I don't want to change the header files because I didn't write them. (I'm still not 100% sure how "extern C" works.)
The interface declared extern "C" must itself be valid C; so the interface:
May not be a class member
May not be overloaded
May not involve class types
May not have optional arguments
Must be syntactically valid as C code.
You can use POD structs so long as they themselves are declared extern "C" in C++ compilation. In C, unlike C++ struct, enum and union tags are not on their own type names, so must be explicitly qualified, or a typedef alias defined.
Note that the following:
#if defined __cplusplus
extern "C"
{
#endif
// Declarations must be valid C syntax
int function() ;
#if defined __cplusplus
}
#endif
Resolves to:
extern "C"
{
// Declarations must be valid C syntax
int function() ;
}
in C++, and just:
// Declarations must be valid C syntax
int function() ;
in C
The important point is that when compiled as C code, nothing C++ specific may be included.
The extern "C" is C++ syntax to switch of all symbol name mangling that is necessary to support overloading, class membership, and optional parameters etc. and which is not valid C. It forces the symbol name in C++ compilation to be the same as that in C compilation.
In C you need to define an enum as a type or actually prefix it with the word enum when you use it like a type name.
So either you need to modify the definition
//replace this:
enum Enum2{A,B,C,D};
//with this
typedef enum{A,B,C,D} Enum2;
or you can keep the definition the same and change the function signature to
FUNC_API(int) Function(Type1 var1, enum Enum2 var2, Type3 var3, void* ptr);
The fact of the matter is that C and C++ are two distinct languages and if the header wasn't written with one of the two in mind, then you can just not use it without modifying it.
edit: as #Clifford mentioned, the same goes for struct types.
struct Type1 //this is passed as "struct Type1 pName"
{
int a,b,c;
};
typedef struct //this is passed as "Type2 pName"
{
int a,b,c;
}Type2;
//this is passed as either "struct type3 pName" or "type3_t pName"
typedef struct type3
{
int a,b,c;
}type3_t;

C2732 - Linkage specification error

I'm using VS2008. I'm getting the following error.
BUILD: [02:0000000295:ERRORE] c:\wince700\platform\am33x_bsp\src\bootloader\bootpart\bootpart_e.cpp(61) : error C2732: linkage specification contradicts earlier specification for 'SdhcInitialize' {log="C:\WINCE700\platform\AM33X_BSP\SRC\BOOTLOADER\bldsys.log(103)"}
BUILD: [02:0000000297:ERRORE] NMAKE : fatal error U1077: 'C:\WINCE700\sdk\bin\i386\ARM\cl.EXE' : return code '0x2' {log="C:\WINCE700\platform\AM33X_BSP\SRC\BOOTLOADER\bldsys.log(104)"}
BUILD: [02:0000000299:ERRORE] clean TargetCompilePass -nologo BUILDMSG=Stop. BUILDROOT=C:\WINCE700\platform\AM33X_BSP CLEANBUILD=1 NOLINK=1 NOPASS0=1 failed - rc = 2. {log="C:\WINCE700\platform\AM33X_BSP\SRC\BOOTLOADER\bldsys.log(105)"}
file_1.cpp
extern "C"
{
// some extern declarations
extern void SdhcInitialize(DWORD slot);
}
file_2.c
void SdhcInitialize(DWORD slot)
{
//some code
}
Please guide me how to resolve.
I'm guessing that you have a header that contains a prototype for the SdhcInitialize() function, and that the header was written for use by C programs. So for example, the header file might include something like the following line:
SD_API_STATUS SdhcInitialize(DWORD slot);
without being enclosed in an extern "C" {} block (since the header is intended for C programs).
Additionally, I suspect that this header is being included - directly or indirectly - by file_1.cpp
This means that the header cannot be included in a C++ program without some additional work being done, otherwise the C++ program will see the declaration as meaning that SdhcInitialize() has C++ linkage.
You have two reasonable approaches to fixing this:
if you can modify the header, add the following lines around the declarations in the header:
#if __cplusplus
extern "C" {
#endif
// declarations go here
#if __cplusplus
}
#endif
This way, C++ files will have the declarations enclosed in a extern "C" linkage block, while C program will not see the extern "C" bits (which would otherwise confuse the C compiler).
I think an argument can be made that all C headers should include something like those lines so that the C functions can be consumed by C++ programs without hassle.
if you cannot modify the header for some reason, you can work around the problem by including the header in C++ files like so:
extern "C" {
#include "Sdhc-header.h"
}
If you surround a set of function declaration by extern "C" { ... }, you don't need to use an additionnal externkeyword in front of the function identifier.
extern "C"
{
// some extern declarations
SD_API_STATUS SdhcInitialize(DWORD slot);
}
When you try to include the "some header files of C" file in "C++ file"(the header file has some where extern "C" for some functions).
include the header earlier will solve the problem.
e.g. Try to move #include "myHeader.h" on the top lines of your C++ file.
This solves my problems.
Hope it helps....
I have solved this as follows (the other solutions did not work for me):
In the file vector.cc:
#define __INVECTOR //solves
#include "vector.h"
In vector.h:
#ifndef __INVECTOR
void function(...etc..);
#endif
This way the declaration isn't read unless we want to call the function from a different file.

Including C++ header file with namespace in C source file causes compilation error

I'm not an expert C++ programmer, and i have been recently doing a trick thing in C++ which is causing me the below issue.
Objective of my task: Specific non system thread (cooperative threading actually) safe module is duplicated to create a system thread safe version to support different needs in the system. But instead of creating sys_XXX functions to keep the compatibility, we have decided to create a namespace to protect the system thread version in a C++ header file. I can actually include this in the CPP file and work happily but i just realised my funcInit call is not called before it reaches the CPP file control. Unfortunately this init for the cooperative threading version is in a C file. Now i need to init my system thread safe version from the same place, but im have been blocked by the compilation error which are hard to solve from my knowledge.
Compilation Error log:-
In file included from sysinit.c:87:
sys_unicode.h:39: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'SystemThreadUtils' <== corresponds to line [namespace SystemThreadUtils {]
sysinit.c:88:
sysinit.c:512: error: expected identifier or '(' before string constant <== corresponds to line [extern "C" bool SystemThreadUtils::funcInit(void);]
sysinit.c:513: error: expected identifier or '(' before string constant <== corresponds to line [extern "C" bool SystemThreadUtils::funcTerm(void);]
sysinit.c: In function 'SysInit':
sysinit.c:817: error: 'SystemThreadUtils' undeclared (first use in this function) <= corresponds to line [SystemThreadUtils::funcInit();]
sysinit.c:817: error: (Each undeclared identifier is reported only once
sysinit.c:817: error: for each function it appears in.)
sysinit.c:817: error: expected ')' before ':' token
sysinit.c: In function 'SysTerm':
sysinit.c:2737: error: expected expression before ':' token <== corresponds to line [SystemThreadUtils::funcTerm();]
sysinit.c:2737: warning: label 'SystemThreadUtils' defined but not used
Source and header snippets FYI :-
C header file (unicode.h):
// all functions called from the C source file
funcInit();
funcA();
funcB();
funcTerm();
C header file (unicode.c):
// all functions called from the C source file
funcInit() {
}
funcA() {
}
funcB() {
}
funcTerm() {
}
C++ header file (sys_unicode.h):
#include "unicode.h"
namespace SystemThreadUtils {
// below functions called from the C source file
extern "C" funcInit();
extern "C" funcTerm();
// below functions called from the CPP source file
funcA();
funcB();
}
C++ source definition (sys_unicode.cpp):
#include "sys_unicode.h"
namespace SystemThreadUtils {
// below functions are called from C source
funcInit() {
}
funcTerm() {
}
// below methods are called from CPP source
funcA() {
}
funcB() {
}
}
CPP source # 1 (utils.cpp):
#include "sys_unicode.h"
using namespace SystemThreadUtils;
utils::utils_init()
{
funcA();
funcB();
}
C source #2 (sysinit.c):
#include "sys_unicode.h"
extern "C" bool SystemThreadUtils::funcInit(void);
extern "C" bool SystemThreadUtils::funcTerm(void);
SysInit ()
{
funcInit(); // non system thread safe version
SystemThreadUtils::funcInit(); // system thread safe version
}
SysTerm ()
{
funcTerm(); // non system thread safe version
SystemThreadUtils::funcTerm(); // system thread safe version
}
You cannot use namespaces in C, extern "C" also is not allowed in C. So what could be a solution: Your C++ module defines a set of functions in namespace SystemThreadUtils that need to get called in C-Code. Since you cannot do that directly, you will have to write a C-conformant wrapper around them:
//C/C++ - header "sys_unicode_for_c.h"
#ifdef __cplusplus
extern "C" {
#endif
void STU_funcInit();
void STU_funcTerm();
#ifdef __cplusplus
} //end extern "C"
#endif
//C++-source: sys_unicode_for_c.hpp
#include "sys_unicode.h"
extern "C" {
void STU_funcInit() {
SystemThreadUtils::funcInit();
}
void STU_funcTerm() {
SystemThreadUtils::funcTerm();
}
}
Meaning: you need a header that is valid C code and declares a delegating function for each C++ function you need to call from C. The source is in C++ and just does the call.
See Calling C++ functions from C file as well.

Use bison and flex with vc6

When i use bison & flex with vc6, i got got below errors
lex.yy.c(395) : error C2146: syntax error : missing ';' before identifier 'YY_PROTO'
lex.yy.c(395) : fatal error C1004: unexpected end of file found
what would be the cause for this??
please help.
Copied from Comment:
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap YY_PROTO(( void ));
#else
extern int yywrap YY_PROTO(( void ));
#endif
#endif
The YY_PROTO macro is only to support old pre-standard C without support for prototypes. You will have hard to find a compiler that does not support that today. That means that as a first debugging step you could try to remove it completely since you want to use prototypes, i.e. modify lex.yy.c to the following:
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap ( void );
#else
extern int yywrap ( void );
#endif
#endif
I know that lex.yy.c is a generated file, so that will not be a permanent fix, but it should at least confirm that the problem is related to the definition of YY_PROTO.
YY_PROTO is a macro that is defined earlier in the same file, so something odd is going on near the macro definition. Search earlier in the file to see how YY_PROTO is defined -- if its not getting defined, your compiler is doing something very weird.