How do I use C Headers in a C++ Program? - c++

I am working on a project in Visual Studio 2010 which is to produce a win 32 dll file. The examples I have are C files and the compile and work well. I would like to incorporate some functionality from C++ function I've written but I have hit a bit of a wall.
If I attempt to link the C++ functions to the C program, it knows nothing about strings, etc and just doesn't work at all (of course).
So I am left with changing the example into a C++ program, then I can use my other files with impunity. When I attempt to do this I get a link error that I don't understand and am uncertain about how to resolve.
The examples use vendor provided headers, which include statements such as
typedef void ( __cdecl *BINDING_PROC_BEVNT)(WORD_T choice, INT_T * pStatus,
I_EVNT_T * pIn, O_EVNT_T * pOut);
In the body of the main code, following the examples:
extern BINDING_PROC_BEVNT b_evnt;
Which then allows you to write
b_evnt(choice, &status, &inpEvent, &outpEvent);
In a vendor provided C file, these are again referenced as:
BINDING_PROC_BEVNT b_evnt;
b_evnt = (BINDING_PROC_BEVNT)GetProcAddress(hCNCMod, "bevnt");
The linker error I am seeing is:
error LNK2001: unresolved external symbol "void (__cdecl* b_evnt)(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)" (?b_evnt##3P6AXGPAFPATI_EVNT_T##PATO_EVNT_T###ZA)
If I rename my main file and recompile as a C program, and omit my C++ functions, everything compiles perfectly. Even when the main file is processed as a C++ file, Intellisense seems to recognize the definitions (hovering over shows the correct definitions).
Additionally I attempted to add extern "C" to a few different locations but it didn't seem to make a difference in the C++ files, and generated a compile error in the C files (about not knowing about strings).
Any insight would be appreciated, I may have simply stared at this too long today to be picking up on something obvious, or it may be something I'm completely unaware of.
Thanks for the help!

If you are compiling against a library that has C-language bindings, you have to tell C++ explicitly that the header files for the library reference C-objects, not C++ objects, or C++ name mangling will prevent correct linking. Often you can do this like so:
extern "C" {
#include "vendor.h"
}
This will tell the C++ compiler that the symbols between the braces are C symbols, and should not have name mangling applied.

To include a C header file from C++, do something like this:
test.cpp
extern "C" {
#include "c_header_file.h"
}
It sounds like the above is what you might need to do to include the vendor header file in your C++ code.
Relatedly, to make a header file automatically work for both C and C++:
c_header_file.h
#ifdef __cplusplus
extern "C" {
#endif
void f(int);
// all declarations go here
#ifdef __cplusplus
}
#endif
Not all vendor-provided header files will contain the above __cplusplus detection, so you will have to wrap them manually in extern "C" as in the first example.

error LNK2001: unresolved external symbol "void (__cdecl* b_evnt)
(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)"
(?b_evnt##3P6AXGPAFPATI_EVNT_T##PATO_EVNT_T###ZA)
That means, the C++ mangled variable b_evnt can't be found. That's true, because it should've been C mangled (just an _ prefix). To fix that, tell it to the compiler in the header when compiling for C++:
#ifdef __cplusplus
extern "C" BINDING_PROC_BEVNT b_evnt;
#else
extern BINDING_PROC_BEVNT b_evnt;
#endif
If that's all, you're done. If there are more symbols you need, you might want to use Greg's solution instead - but be aware that that is also not a fixall.

Your vendor provided headers are being included in a C++ compilation unit, but they aren't prepared for C++. So the declarations of the functions are being compiled with name mangling the C++ compielr requires to support overloading.
The headers need to be wrapped in an extern "C" {} block to let the C++ compiler know that these declarations use a C linkage.
Probably the easiest way to do this it to use your own wrapper headers that do something like:
#ifndef FOO_WRAPPER_H
#define FOO_WRAPPER_H
#if __cplusplus
extern "C" {
#endif
#include "foo.h"
#if __cplusplus
}
#endif
#endif
And include yiour wrapper header instead of the vendor's header - the wrapper will work for wither C or C++ compiles.
Also, contact your library vendor and let them know they should make these changes - users of the library shouldn't have to do this workaround to use the library from C++.

Related

How to import the C static Libraries in windows forms application vc++

I have created one static "C" library using VS.
I am using the same library file for another VS console C application its working fine but when I am working with windows forms app it's not working.
Referred so many queries in this forum but didn't get the Help.
Is there any naming conventions to call the static library functions from the Windows forms Managed c++ ?
Getting Errors Like this
error LNK2028: unresolved token (0A000032) "enum STATUS __clrcall
xyz(unsigned char)" (?xyz##$$FYM?AW4STATUS##E#Z) referenced in
function
__catch$?button3_Click#Form1#Myapp##$$FA$AAMXP$AAVObject#System##P$AAVEventArgs#4##Z$0
But I should use the same static library for both console and windows application.
The linker error message gives a strong hint what it going wrong. Note the __clrcall calling convention for the undefined symbol, it tells you that the compiler thinks that these are "CLR" functions. Managed code, of course they are not, they are __cdecl. There's more, the names are also mangled. Note the "##$$FYM?AW4STATUS##E#Z" curses in the name. Which tells you that the compiler thinks they were written in C++ instead of C.
You'll have to explicitly tell the compiler about this, the .h file isn't compatible enough. Which you do like this in your C++/CLI source code file:
#pragma managed(push, off)
extern "C" {
#include "yadayada.h"
}
#pragma managed(pop)
The #pragmas temporarily turn off managed code compilation mode so the compiler will now assume these are unmanaged function declarations. The extern "C" {} wrap around the #include tells the compiler that the .h file contains C declarations.

Apple Mach-O Linker Error, due to file extension

The dreaded typical linker error..
ld: symbol(s) not found for architecture armv6
collect2: ld returned 1 exit status
However, it is caused by filename? I use C++/Objective-C, so all of my Obj-C files are .mm, but I can never use any .c files. For example I've included the SFMT algorithm in my project, which was giving me these errors, but just changing the single .c file to .cpp made it go away and the code works just fine! I am only including the headers, so I'm not sure why this makes any difference.
The problem now is I'm trying to include Freetype2, giving me the same issue (pretty sure it's because it's .c), but that is far too large to rename every file, and I'm also using a linked binary, so unless I recompile it with new filenames, I can't change that. So now it's time to find the real reason behind this.
Any idea why this would happen? How can I stop linker errors for .c files?
Wrap your Freetype includes within an extern "C" directive:
// Non-C includes
#include <iostream>
extern "C"
{
#include <freetype/freetype.h>
// ... Other freetype includes
}
You can probably use #import instead of #include within an extern "C" directive. I've never tried, but I don't see why it wouldn't work.
Surround your c header file with this. This can also surround the include:
#ifdef __cplusplus
extern "C" {
#endif
// function declarations etc if this is your own header.
// OR you can use this in the .mm file to surround your include.
//...
#ifdef __cplusplus
};
#endif
This specifies external linkage for your c functions.
If you don't do this when you include your c .h files the C++ compiler will mangle in a different way from the C compiler, and cause problems for the linker.
By using extern "C", you are telling your C++ compiler to use C-style mangling of the functions.

Linking to a C library compiled as C++

I'm in linker paradise now. I have a C library which only compiles in Visual C++ (it probably works in gcc) if:
I compile it as C++ code
Define __cplusplus which results in all the declarations being enclosed in extern "C" { }
So, by doing this I have a static library called, say, bsbs.lib
Now, I have a C++ project called Tester which would like to call function barbar in declared in bsbs.h. All goes fine, until I try to link to bsbs.lib where I get the all-too-familiar:
Tester.obj : error LNK2001: unresolved external symbol _foofoo
And it always seems to be foofoo which cannot be resolved regardless of which function I call in Tester (barbar or anything else).
Update: I've expanded on Point 2 as requested. Thanks a lot for the help guys!
#ifndef _BSBS_H
#define _BSBS_H
/* Prevent C++ programs from name mangling these definitions. */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <setjmp.h>
.......
.......
#ifdef __cplusplus
}
#endif
#endif /* _BSBS_H */
This is the "main" header file, so to speak. All the important functions are here. But there are other header files called by the bsbs.c file which are not enclosed in extern "C" {}.
Solved:
OK, this is quite weird, but I removed the extern C bit from the header file in bsbs, compiled it as a C++ project (even though all the files are .c and removed the __cplusplus define) and it worked! I got the idea after looking at the symbol list. Everything was mangled except the ones enclosed in extern C (doh) and it was asking for an unmangled symbol so I figured something was amiss.
If you declare them as extern C in the lib (which is unnecessary, if you're calling them from C++), then they must be extern C in your headers.
There may be a dependency in the c library you're not including in your link. Does the c library you're including really a reference to a DLL? If so there's a program called 'depends' which will tell you what the other required DLL's are.
I'm assuming you've added a linker reference. E.g.:
#pragma comment(lib, "bsbs.lib")
Perhaps the compiler/linker combination needs to be made aware of which APIs are to be exported/imported? If so I'd try adding the appropriate __declspec (e.g., dllimport and/or dllexport) to the C++ library.
Does your lib file import any other lib files? You can compile a lib file to either explicity link lib files or implicitly. One way you get the lib files in a huge ball, the other you get them as separate libs that all need linked at compile time in the final app. If foofoo is imported in your lib file from another lib file, then include that lib file in your final project. This is my best guess from what you described, and is by far the most common thing I get asked when dealing with lib files thru co-workers..

Using extern to include files in C or C++

How this works in C or C++?
extern "C" {
#include <unistd.h>
#include <fd_config.h>
#include <ut_trace.h>
#include <sys/stat.h>
#include <sys/types.h>
}
The C++ standard does not specify how compilers should name the symbols in their object files (for instance, Foo::bar() might end up as __clsFoo_fncBar or some gobbledygook). The C standard does, and it is almost always different from how C++ compilers do it (C doesn't have to deal with classes, namespaces, overloading, etc.).
As a result, when you are linking against an object file that was output by a C compiler, you have to tell your C++ compiler to look for symbols with names that correspond to the C standard. You are essentially putting it in "C mode." This is what the "C" part of extern "C" does.
(Alternatively, you might also be declaring functions or variables that could be used by an external C object file. In this case, it means export those symbols the C way.)
If your Project has C and C++ source files and you need to build as a whole( C files calls some functions in C++ files) ,so we need to protect the C file function calls and symbols by declaring as in C++ files by
extern "C"
{
/symbols used in c files/
uint8 GetCurrentthreadState(HANDLE ThreadId)
}
Then the C++ complier generate compilation output which is same as that of C complier for the above declared functions and symbols.So on linking time , the compiler can easily link the C and C++ defined symbols with out any link error.
So my opinion is not needed to give the #ifdef __cplusplus check on compilation.
Because we need to protect the symbols in c++ files right? Also C++ files can be compiled by C++ compiler only right?
/renjith g
It will not work, you need to add the cplusplus preprocessor...
#ifdef __cplusplus
extern "C" {
#endif
// your code
#ifdef __cplusplus
}
#endif
EDIT:
In C++, the name will be treated like in C which mean that there will be no mangle name. It allows to make the difference between two C++ different function with different argument type/number or a different namespace in a library (for library purpose libname.so, libname.a). If the name is mangled, the C program will not be able to recognize it
eg:
int myfction()
void myfunction(int)
void myfunction(int, char)
C library: myfction
C++ library: int_myction (it depend on your compiler)
C++ library: int_myction_int (it depend on your compiler)
C++ library: int_myction_int_char (it depend on your compiler)
// ... which is not allowed in C program
Every C++ Compiler needs to support the extern "C" linkage.
The code in such block could be legacy code written in C for a certain functionality, which is required for the current program.
How this is implemented is mostly compiler dependent, However I heard that many Compilers disable the name mangling and change the calling convention.

Can't access variable in C++ DLL from a C app

I'm stuck on a fix to a legacy Visual C++ 6 app. In the C++ DLL source I have put
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
which results in MyNewVariable showing up (nicely undecorated) in the export table (as shown by dumpbin /exports blah.dll). However, I can't figure out how to declare the variable so that I can access it in a C source file. I have tried various things, including
_declspec(dllimport) char* MyNewVariable;
but that just gives me a linker error:
unresolved external symbol "__declspec(dllimport) char * MyNewVariable" (__imp_?MyNewVariable##3PADA)
extern "C" _declspec(dllimport) char* MyNewVariable;
as suggested by Tony (and as I tried before) results in a different expected decoration, but still hasn't removed it:
unresolved external symbol __imp__MyNewVariable
How do I write the declaration so that the C++ DLL variable is accessible from the C app?
The Answer
As identified by botismarius and others (many thanks to all), I needed to link with the DLL's .lib. To prevent the name being mangled I needed to declare it (in the C source) with no decorators, which means I needed to use the .lib file.
you must link against the lib generated after compiling the DLL. In the linker options of the project, you must add the .lib file. And yes, you should also declare the variable as:
extern "C" { declspec(dllimport) char MyNewVariable; }
extern "C" is how you remove decoration - it should work to use:
extern "C" declspec(dllimport) char MyNewVariable;
or if you want a header that can be used by C++ or C (with /TC switch)
#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif
And of course, link with the import library generated by the dll doing the export.
I'm not sure who downmodded botismarius, because he's right. The reason is the .lib generated is the import library that makes it easy to simply declare the external variable/function with __declspec(dllimport) and just use it. The import library simply automates the necessary LoadLibrary() and GetProcAddress() calls. Without it, you need to call these manually.
They're both right. The fact that the error message describes __imp_?MyNewVariable##3PADA means that it's looking for the decorated name, so the extern "C" is necessary. However, linking with the import library is also necessary or you'll just get a different link error.
#Graeme: You're right on that, too. I think the "C" compiler that the OP is using is not enforcing C99 standard, but compiling as C++, thus mangling the names. A true C compiler wouldn't understand the "C" part of the extern "C" keyword.
In the dll source code you should have this implementation so that the .lib file exports the symbol:
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
The c client should use a header with this declaration so that the client code will import the symbol:
extern "C" _declspec(dllimport) char* MyNewVariable;
This header will cause a compile error if #include-ed in the dll source code, so it is usually put in an export header that is used only for exported functions and only by clients.
If you need to, you can also create a "universal" header that can be included anywhere that looks like this:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef dll_source_file
#define EXPORTED declspec(dllexport)
#else
#define EXPORTED declspec(dllimport)
#endif dll_source_file
#ifdef __cplusplus
}
#endif
EXPORTED char* MyNewVariable;
Then the dll source code looks like this:
#define dll_source_code
#include "universal_header.h"
EXPORTED char* MyNewVariable = 0;
And the client looks like this:
#include "universal_header.h"
...
MyNewVariable = "Hello, world";
If you do this a lot, the monster #ifdef at the top can go in export_magic.h and universal_header.h becomes:
#include "export_magic.h"
EXPORTED char *MyNewVariable;
I've never used _declspec(dllimport) when I was programming in Windows. You should be able to simply declare
extern "C" char* MyNewVariable;
and link to the .libb created when DLL was compiled.