I have two functions declared as following, using extern "C" aming to avoid name mangling.
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jobject JNICALL Java_com_trident_tv_si_SIManagerImpl_nGetServiceDetails
(JNIEnv *, jobject, jint);
JNIEXPORT jobject JNICALL Java_com_trident_tv_si_SIManagerImpl_nGetServiceCurrentEvent
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
Surprisingly, the second function still have a mangled name _GLOBAL__I_Java_com_trident_tv_si_SIManagerImpl_nGetServiceCurrentEvent , I was wondering what is the purpose of it and why the first function did not generate one?
00004d58 T Java_com_trident_tv_si_SIManagerImpl_nGetServiceCurrentEvent
0000533a T Java_com_trident_tv_si_SIManagerImpl_nGetServiceDetails
0000494f t _GLOBAL__I_Java_com_trident_tv_si_SIManagerImpl_nGetServiceCurrentEvent
EDIT:
Find something here. However, no clear answer yet.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12293
It looks to me like the two functions have the correct names ( the two preceded by T ), and that a third symbol (preceded by t) is created for gccs internal use.
They have been reordered though.
// SECOND FUNCTION, T = exported and in TEXT section
00004d58 T Java_com_trident_tv_si_SIManagerImpl_nGetServiceCurrentEvent
// FIRST FUNCTION, T = exported and in TEXT section
0000533a T Java_com_trident_tv_si_SIManagerImpl_nGetServiceDetails
// INTERNAL symbol, t = non-exported symbol in TEXT section
0000494f t _GLOBAL__I_Java_com_trident_tv_si_SIManagerImpl_nGetS
Related
I have to use a third-party C++ library (that I can not change) and call its API from C code.
For most of the library APIs I use a wrapper as explained in this post:
How to call C++ function from C?
But there is one API that takes a variable number of arguments.
Here is its definition (from the header file provided with the library):
void consoleDebug(char* format, ...);
I do not see how I can write the wrapper function for this API.
I tried this but it does not work:
extern "C" {
void wrapper_consoleDebug(char * format, ...)
{
va_list argptr;
va_start(argptr,format);
consoleDebug(format, argptr);
va_end(argptr);
}
}
Any idea is welcome! Thanks!
problem of call c++ functions from c that it used different decoration.
all next for cl.exe (msvc) + link.exe toolset, but think other compiler/linkers have analog features
for example when you compile in c++ function
void consoleDebug(char* format, ...)
in obj (or static lib) file will be ?consoleDebug##YAXPEADZZ symbol.
but when you use the same function from c unit - in object file will _consoleDebug (for x86) or consoleDebug (other platforms)
if we declare in c file
void consoleDebug(char* format, ...)
and do call - in obj will be stored that external symbol consoleDebug (or _consoleDebug) used. when linker will be build code - it will search - where is [_]consoleDebug actually defined (in all obj and lib passed to him) and founf nothing - no such symbol. as result we got error unresolved external symbol [_]consoleDebug
solution here in undocumented linker option /alternatename :
/alternatename:sym1=sym2
with this we say to linker (link.exe) if he need sym1 symbol and can not found it - try use sym2 instead. with this we can create next solution:
1 - we need know exactly symbol name in c++ - we can get it with __FUNCDNAME__ macro:
for example:
#define _GET_NAMES_
#ifdef _GET_NAMES_
void consoleDebug(char* format, ...)
{
#pragma message(__FUNCSIG__ ";\r\n")
#pragma message("__pragma(comment(linker, \"/alternatename:" __FUNCTION__ "=" __FUNCDNAME__ "\"))")
}
#endif // _GET_NAMES_
this is temporary, fake code, need only for print __FUNCDNAME__
then in c file we declare
void __cdecl consoleDebug(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebug=?consoleDebug##YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebug=?consoleDebug##YAXPEADZZ"))
#endif
and can free use consoleDebug
in case we have multiple functions in c++ with same short name, say
void consoleDebug(char* format, ...);
void consoleDebug(wchar_t* format, ...);
this is also easy work, need only bit different name this 2 api in c code:
void __cdecl consoleDebugA(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebugA=?consoleDebug##YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebugA=?consoleDebug##YAXPEADZZ"))
#endif
void __cdecl consoleDebugW(wchar_t *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebugW=?consoleDebug##YAXPA_WZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebugW=?consoleDebug##YAXPEA_WZZ"))
#endif
after this we can simply call like
consoleDebugA("str %u\n", 1);
consoleDebugW(L"str %u\n", 2);
from c code.
no any shim/wrapper code need with this. in case you use not cl/link but other tool-chain and can not found analog of /alternatename name option - possible use asm file for create single jmp shim. say for x64
extern ?consoleDebug##YAXPEADZZ:proc
extern ?consoleDebug##YAXPEA_WZZ:proc
_TEXT segment 'CODE'
consoleDebugA proc
jmp ?consoleDebug##YAXPEADZZ
consoleDebugA endp
consoleDebugW proc
jmp ?consoleDebug##YAXPEA_WZZ
consoleDebugW endp
_TEXT ENDS
END
Thanks for your help!
I tried the suggestion from Sam Varshavchik and it works (at least in my case)! More precisely, here is what I did:
// wrapper.cpp
extern "C" { void (*wrapper_consoleDebug)(char * format, ...) = consoleDebug;}
// wrapper.h
extern void (*wrapper_consoleDebug)(char * format, ...);
// C file
#include "wrapper.h"
// in my code
wrapper_consoleDebug("my logger is %s","great");
I did not try the other suggestions yet, but I guess they would work too.
Thanks again!
I want to declare printf function by myself, and try if the code can work.
I looked into the <stdio.h> and found it declared as:
_Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);
Then I found
_Check_return_opt_ defined in <crtdefs.h>
_CRTIMP defined in <crtdefs.h>
_In_z_ _Printf_format_string_ defined in <sal.h>
So my code is as:
#include <crtdefs.h>
#include <sal.h>
_Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);
int main()
{
int a = 100;
printf("%d\n",a);
}
I guess this will work, but it gets an error:
error LNK2019: unresolved external symbol ...
What's wrong with my code? Are there anything I missed in <stdio.h>?
I have already read a question on stackoverflow.
(https://stackoverflow.com/questions/25155631/microsoft-visual-studio-2012-version-of-printf-function-declaration)
It helps, but doesn't solve my problem.
I also learn to know that an extern "C" function works fine. such as:
extern "C" int printf (const char * __format, ...);
But I think this still not accounts for my doubt.
In stdio.h, was the prototype for printf inside an extern "C" {} block? Note that this block could be large and so you might not have noticed it. If so, you need to use extern "C" around your prototype.
The extern "C" should remove your doubt - without that you are compiling the declaration as C++ which doesn't use a linking convention that's the same as C (which is how printf() is compiled in the library).
You can fix the problem using extern "C" or compiling your program as a C program instead of C++ (change the name of the source file to have a .cextension).
I have these two namespaces, each one containing a function with the same name, like
namespace group1 {
void add(int arg) {
}
}
namespace group2 {
void add(bool arg) {
}
}
and I specify this in the header with the declarations
#ifdef __cplusplus
extern "C" {
#endif
// My namespaces and functions prototypes here
#ifdef __cplusplus
}
#endif
and I am trying to export them into a DLL, with GCC. I get a warning about a conflict between them because they have the same name, then an error at linking time. I thought the name was mangled in the object file based on the arguments, too. I don't know if the linker cares about the namespace too. How could I make this work? Thanks.
If these are C++ functions, you have to remove the extern "C" bracketing:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
extern "C" tells the compiler "don't mangle this name"--but (as you say) you want the mangling.
You can't really do that directly. When you use the extern "C", you are declaring that the functions are exported as if they were C functions, not C++.
This means (among other things)
Namespaces are removed, and are not considered part of the name
No name mangling due to arguments is done
The best you can do is create extern "C" functions which redirect.
#ifdef __cplusplus
extern "C" {
#endif
void group1_add(int arg);
void group2_add(bool arg);
#ifdef __cplusplus
}
#endif
And the implementations of the wrapper functions would then use either group1::add() or group2::add() as appropriate.
If I try to implement my class on this file I get an error UnsatisfiedLinkError, however if I remove the implementation of the Broker.h Class it goes ok. Why?
Broker.h
#include "XletTable.h"
#ifndef BROKER_H_
#define BROKER_H_
class Broker {
private:
static Broker* brokerSingleton;
static XletTable *table;
// Private constructor for singleton
Broker(JNIEnv *, XletTable *);
// Get XletTable (Hash Table) that contains the...
static XletTable* getTable();
public:
virtual ~Broker();
static Broker* getInstance(JNIEnv *);
jobject callMethod(JNIEnv *, jclass, jstring, jobject, jbyteArray);
};
#endif /* BROKER_H_ */
BrokerJNI.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Broker */
#ifndef _Included_Broker
#define _Included_Broker
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Broker
* Method: callMethod
* Signature: (Ljava/lang/String;Ljava/lang/reflect/Method;[B)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_Broker_callMethod
(JNIEnv *, jclass, jstring, jobject, jbyteArray);
#ifdef __cplusplus
}
#endif
#endif
Probably your library miss reference to some symbol, or another library. Try make some main.cpp with empty main() function, and link it with your library - g++ main.cpp -o main -lInterAppCC. If you miss something, the linker will give you a detailed error message.
PS. Since your header file already wraps function prototype with extern "C", you don't required to do the same when writing implementation.
You need to use extern "C" around the JNIEXPORT stuff, to avoid c++ name mangling of the JNI functions.
C++ name mangling changes function names (in the obj-files) to include the types of parameters, virtual-ness, etc, to be able to link different overloaded functions with the same name.
So, wrap your JNIEXPORT with extern "C" { ... } (look at the JNI header) and make sure your c++-code isn't wrapped in the same.
MyHeader.h
#ifndef __MYHEADER_H
#define __MYHEADER_H
#ifdef __cplusplus
extern "C"{
#endif
void dchar(unsigned char);
void char*(char c);
#ifdef __cplusplus
}
#endif
#endif
Errors
Declaration syntax error
Ambiguity between dchar(unsigned char) and dchar (char)
The program is on the website.
You are using C linkage in your program, this means names will not be mangled by the compiler. In your example, you declare two functions named dchar, one taking an unsigned char argument, one taking a char argument. Because of the C linkage, these will both appear to the linker using the name dchar instead of the usual mangled name. The linker cannot see the difference between these two functions, and will throw an error, since it thinks you implemented the same function twice.
Since you marked this question as C++, you could solve this by simply removing the extern "C" declaration, if you want to use these functions in C too, you will need to change the name of one function.