Howcome some C++ functions with unspecified linkage build with C linkage? - c++

This is something that makes me fairly perplexed.
I have a C++ file that implements a set of functions, and a header file that defines prototypes for them.
When building with Visual Studio or MingW-gcc, I get linking errors on two of the functions, and adding an 'extern "C"' qualifier resolved the error. How is this possible?
Header file, "some_header.h":
// Definition of struct DEMO_GLOBAL_DATA omitted
DWORD WINAPI ThreadFunction(LPVOID lpData);
void WriteLogString(void *pUserData, const char *pString, unsigned long nStringLen);
void CheckValid(DEMO_GLOBAL_DATA *pData);
int HandleStart(DEMO_GLOBAL_DATA * pDAta, TCHAR * pLogFileName);
void HandleEnd(DEMO_GLOBAL_DATA *pData);
C++ file, "some_implementation.cpp"
#include "some_header.h"
DWORD WINAPI ThreadFunction(LPVOID lpData) { /* omitted */ }
void WriteLogString(void *pUserData, const char *pString, unsigned long nStringLen) { /* omitted */ }
void CheckValid(DEMO_GLOBAL_DATA *pData) { /* omitted */ }
int HandleStart(DEMO_GLOBAL_DATA * pDAta, TCHAR * pLogFileName) { /* omitted */ }
void HandleEnd(DEMO_GLOBAL_DATA *pData) { /* omitted */ }
The implementations compile without warnings, but when linking with the UI code that calls these, I get a normal
error LNK2001: unresolved external symbol "int __cdecl HandleStart(struct _DEMO_GLOBAL_DATA *, wchar_t *)
error LNK2001: unresolved external symbol "void __cdecl CheckValid(struct _DEMO_MAIN_GLOBAL_DATA *
What really confuses me, now, is that only these two functions (HandleStart and CheckValid) seems to be built with C linkage. Explicitly adding "extern 'C'" declarations for only these two resolved the linking error, and the application builds and runs.
Adding "extern 'C'" on some other function, such as HandleEnd, introduces a new linking error, so that one is obviously compiled correctly.
The implementation file is never modified in any of this, only the prototypes.

The error indicates that nothing is wrong with your implementation file or header (as used by the implementation file) - the link error strongly suggests that the functions actually generated were generated with c++ linkage - Its the UI file thats incorrectly looking for the C-Linkage versions of the functions. Patching the definitions in the header is patching your implementation to conform to the probably incorrect demands of the UI, rather than the other way around.
Your UI file is either a .m or .c file, OR , if your UI file is a .cpp file you have dome something like:
// ui.cpp
extern "C" {
#include "some_header.h"
}
Of course, if your UI file is a .c file - you either need to change it to cpp, OR explicitly define the functions with C-linkage so they can be called from C.

Could the function names conflict with names declared in a header?
Do you get the same problem if you give the functions different names?

Related

How to access global variable in C source file from c++ source file

There is a very big C file, which defined a lot of strings and used locally. I would like to do access these strings from a C++ file, but using extern "C" does not help.
The C file look like this: data.c
#include <stdio.h>
static char* str = "string\n";
void p() {
printf(str);
}
and the c++ file look like this:
#include <iostream>
extern "C" {
extern char* str;
extern void p();
};
int main(int argc, char* argv[]) {
p();
std::cout << str;
return 0;
}
I am using VS2013, the compile gives error
error LNK2001: unresolved external symbol _str
fatal error LNK1120: 1 unresolved externals
Calling the functions defined in C file has no problem.
Is it even possible to access the variables in C from C++? And how to do it correctly?
when you are using static keyword in your file. it indicates that the variable prefixed with static can't be exported in another file. you can keep that variable as non static and then it is possible to access those variables in another files as well.
you can refer the following article.
https://cboard.cprogramming.com/cplusplus-programming/102259-global-variable-access-c-cplusplus.html
In C, the static statement implies that the symbol should NOT be exported.
Thus, it is possible to access those variables simply by removing that keyword.
This article might help you understand better the symbol visibility concept
Apart from that, while C might have trouble using mangled C++ symbols, the opposite poses absolutely no compatibility issue.

Why new VS2013 project's functions are unresolved in linking if file is .cpp, but ok if file is .c

I'm linking all the native libs to a .dll which is used in WPF application.
I'm done this with other projects that are compiled to libs but the latest one does not work somehow, although all seems to be same way. I did like this:
.h:
#ifndef MYHEADER_H_
#define MYHEADER_H_
#ifdef __cplusplus
extern "C" {
#endif
void MySetLoginResultCallback(int(*Callback)(int Ok, const char *UserName));
#ifdef __cplusplus
} // end of extern "C"
#endif
#endif // MYHEADER_H_
.cpp:
typedef int(*LoginResultCB_t)(int IsOk, const char *UserName);
LoginResultCB_t gLoginResultCB;
void MySetLoginResultCallback(LoginResultCB_t pCB)
{
gLoginResultCB = pCB;
}
extern "C" __declspec(dllexport) int MyLoginResultCB(int Ok, cons char *UserName)
{
if (gLoginResultCB)
return gLoginResultCB(Ok, UserName);
return -1;
}
MyLoginResultCB is imported to WPF exe and called from there. In initialization the MySetLoginResultCallback is called from a C-file in native .dll.
In .dll linking I get unresolved error from MySetLoginResultCallback (which is called in native .c file). If I leave the header exactly the same and rename .cpp -> .c and remove extern "C" the .dll linking succeeds. What am I missing here?
call from aini.c
MySetLoginResultCallback(XpAfterLoginCB);
error:
1>aini.obj : error LNK2019: unresolved external symbol _MySetLoginResultCallback referenced in function _InitNoAKit
In your .cpp file, you're defining a function MySetLoginResultCallback with C++ language linkage. That's a different function than the function MySetLoginResultCallback with C language linkage declared in the .h file.
The correct solution would be to add C language linkage to the .cpp file:
extern "C" {
typedef int(*LoginResultCB_t)(int IsOk, const char *UserName);
LoginResultCB_t gLoginResultCB;
void MySetLoginResultCallback(LoginResultCB_t pCB)
{
gLoginResultCB = pCB;
}
}
Notice that function types have language linkage too, which means that the typedef LoginResultCB_t has to be declared with C language linkage in the .cpp file also, because the parameter is declared as such in the .h file.
The reason the way that extern "C" definitions ONLY in .h file worked in other projects/libs is that I included my header file with function declarations in my .cpp file with the definitions. Thanks to #molbdnilo to point this out!

LNK2019: unresolved external symbol in function

I'm using VS2008 WinCE7. I'm facing linking error during build.
The file system structure is
menu.c - ./menu.c
eboot.h - ./eboot.h
file_1.cpp - ./dir1/file_1.cpp
where . represents current directory
menu.c
#include <eboot.h>
static VOID OALWriteToEMMC(OAL_BLMENU_ITEM *pMenu);
VOID OALWriteToEMMC(OAL_BLMENU_ITEM *pMenu)
{
OALTestEMMC();
}
file_1.cpp
#include <eboot.h>
VOID OALTestEMMC();
VOID OALTestEMMC()
{
//some code
}
eboot.h
VOID OALTestEMMC();
I'm getting the error
menu.obj : error LNK2019: unresolved external symbol OALTestEMMC referenced in function OALWriteToEMMC
Please guide me how to solve it.
EDIT1:
menu.c
#ifdef __cplusplus
extern "C" VOID OALTestEMMC();
#endif
and removed the declaration in eboot.h and added it in file_1.cpp
But, the error persists.
It seems that you are compiling the function definition in C++ but the use of that function in C. Without making the function extern "C" in C++, the compiler will mangle the name, and generate a symbol that won't match the declaration used in the C code.
If you want to mix C and C++, make sure that the declarations in C++ are marked extern "C" so that the compiler won't mangle the names and will use the C calling conventions. Alternatively, compile everything in C++ (or in C)
David Rodríguez's original answer is correct. You are invoking a C++ function (OALTestEMMC) from a C source file. As David mentioned, the C++ compiler will mangle the function name. In order to suppress the name mangling so that the code in menu.c can invoke it, place the 'extern "C"' qualifier on the OALTestEMMC function (in file_1.cpp):
extern "C" VOID OALTestEMMC();
extern "C" VOID OALTestEMMC() {
// stuff
}

unresolved external symbol _CLSID_VdsLoader

I'm trying to write a program that can manage the harddisks/volumes/partitions in a Windows system. It seemed like a good idea to use Windows' Virtual Disk Service to accomplish this.
I wrote a bit of code to try it out, but when linking it I get the following error: error LNK2001: unresolved external symbol _CLSID_VdsLoader
Microsofts sample code indicates that I have to link to ole32.lib, and from googling I learned that uuid.lib is also involved. The "Additional Dependencies" line in my project settings is the following:
kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
As you can see, both previously mentioned libraries are included.
I'm trying all this on Visual C++ Express for Windows Desktop 2013. Could this be the problem? Perhaps the express version does not support 100% of the available COM objects? If that's not it, what else could it be?
This is explained here: How to avoid error "LNK2001 unresolved external" by using DEFINE_GUID, you just need for example to add #include <InitGuid.h> in your stdafx.h file.
I had similar issue with unresolved external guid. I didn't define _MIDL_USE_GUIDDEF_ macro and tried to compile code as C++ code.
Since MIDL compiler generates C source file to define guids it is compiled as C code until you explicitly tell visual studio to compile code as C++ code.
MIDL-generated header file contains (when compiled as C++):
extern "C"
{
extern "C" const IID iid; // extern "C" is redundant, extern would be enough
}
MIDL-generated guids-definition file contains (when compiled as C++):
extern "C"
{
const IID iid = { ... }; // _MIDL_USE_GUIDDEF_ macro is not defined
}
We need to remember:
extern "C" block implies C name decoration; e.g.
extern "C" { int a; }
extern "C" singleton implies C name decoration AND extern semantics; e.g.
extern "C" int a;
in C++ non-extern namespace-scope const object implies internal linkage; e.g.
const int a; // internal linkage
extern const int b; // external linkage
With this in mind we can see that header file declares const IID iid with external linkage and C name decoration, whereas guids-definition file defines const IID iid with internal linkage and C name decoration. Linkages do not match, therefore they are treated as different entities by linker. In this case const IID iid with external linkage is left undefined and is later used in the same translation unit.
When you add predefined _MIDL_USE_GUIDDEF_ macro guids-definition file will contain:
extern "C"
{
extern "C" const IID iid = { ... }; // extern "C" is redundant, extern would be enough
}
So you need to add predefined _MIDL_USE_GUIDDEF_ macro in order to explicitly compile code as C++.

Importing a C DLL's functions into a C++ program

I have a 3rd party library that's written in C. It exports all of its functions to a DLL.
I have the .h file, and I'm trying to load the DLL from my C++ program.
The first thing I tried was surrounding the parts where I #include the 3rd party lib in
#ifdef __cplusplus
extern "C" {
#endif
and, at the end
#ifdef __cplusplus
} // extern "C"
#endif
But the problem there was, all of the DLL file function linkage looked like this in their header files:
a_function = (void *)GetProcAddress(dll, "a_function");
While really a_function had type int (*a_function) (int *). Apparently MSVC++ compiler doesn't like this, while MSVC compiler does not seem to mind.
So I went through (brutal torture) and fixed them all to the pattern
typedef int (*_x_a_function) (int *); // using _a_function will not work, C uses it!
_x_a_function a_function ;
Then, to link it to the DLL code, in main():
a_function = (_x_a_function)GetProcAddress(dll, "a_function");
This SEEMS to make the compiler MUCH, MUCH happier, but it STILL complains with this final set of 143 errors, each saying for each of the DLL link attempts:
error LNK2005: _x_a_function already defined in main.obj main.obj
Multiple symbol definition errors.. sounds like a job for extern! SO I went and made ALL the function pointer declarations as follows:
function_pointers.h
typedef int (*_x_a_function) (int *);
extern _x_a_function a_function ;
And in a cpp file:
function_pointers.cpp
#include "function_pointers.h"
_x_a_function a_function ;
ALL fine and dandy.. except for linker errors now of the form:
error LNK2001: unresolved external symbol _a_function main.obj
Main.cpp includes "function_pointers.h", so it should know where to find each of the functions..
I am bamboozled. Does any one have any pointers to get me functional? (Pardon the pun..)
Linker errors like that suggest you've defined all the functions in function_pointers.cpp, but forgotten to add it to the project/makefile.
Either that, or you've forgotten to "extern C" the functions in function_pointers.cpp too.
I believe that if you declared the typedefs and/or the prototype as extern "C", you must remember to extern "C" the definition too.
When you link C functions the prototypes will get a leading _ in front of them by default so
when you do a typedef using the same name
typedef int (*_a_function) (int *);
_a_function a_function
you'll get issues because there is already a function in the dll named _a_function.
Usually you declare a function in yourlibrary.h like extern "C" __declspec(dllexport) int __cdecl factorial(int); then create that function in yourlibrary.c:
extern "C" __declspec(dllexport) int __cdecl factorial(int x) {
if(x == 0)
return 1;
else
return x * factorial(x - 1);
}
After compiling your DLL you get your .dll and .lib files. The latter is used when you want to import your functions to the project. You put #include "yourlibrary.h" and #pragma comment(lib, "yourlibrary.lib") in your project, after this you can use int factorial(int) in you application.