I'm working on an existing c++ project with visual studio, and I found out that almost every function declaration gets a __cdecl in front of the function name, like:void __cdecl functionName(). Then I jump to the definition of __cdecl, which locates in the winnt.h file:
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define NTAPI __stdcall
#else
#define _cdecl
#define __cdecl
#define NTAPI
#endif
I've searched cdecl and got that it's the default calling convention for C and C++ programs, but code above tells me that __cdecl extends to nothing. So why place a __cdecl before function name as it's just nothing ? or did I misunderstand the code above?
what's the meaning of #define __cdecl”
Lines that begin with # are preprocessor directives. #define is a directive that defines a preprocessor macro. #define __cdecl defines a macro with identifier __cdecl and empty replacement. If such macro is defined, the processor will replace all instances of the __cdecl with an empty string.
So why place a __cdecl before function name as it's just nothing ?
Take a look at the directives at the beginning of the definition in question:
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#else
The macro is defined conditionally. When the macro is not defined, __cdecl will not expand to nothing. When not expanded to nothing, __cdecl is a microsoft specific function specifier as you have discovered.
The conditionally defined macro allows one to write code that uses __cdecl on systems that allow it, and automatically remove it on systems that do not.
But I'm still confused with the #if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) line, what does it mean?
It is a preprocessor directive that test whether the macro _MSC_VER has greater value than 800, or if macro _STDCALL_SUPPORTED is defined. If the test is false, then the code between #if and #else is removed. If it is true, then the code between #else and #endif is removed.
It means that if an API is defined as using NTAPI it will generate code that uses the __stdcall calling convention - a variation of the Pascal calling convention in which the callee cleans the stack. With __cdecl, the caller cleans the stack (so it supports variadic type functions).
And all of this is conditional on the #if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
Related
While using a 3rd party shared library i.e. DLL, I have to define the functions usable by their symbol names. So I have to declare some function types.
But the function definition involves a calling convention, in my case __cdecl.
So, naturally, this calling convention is only applicable to the MSVC compiler but I still want to compile my portable API abstraction code, which uses boost::dll with linux, even though I can not execute it on my development linux machine, so I can still check the compile time stuff.
So my idea was to define the __cdecl name to something as nothing or a white space, a NOP if you will, with the pre-processor, but I am not able to do that:
#if !BOOST_OS_WINDOWS
#define __cdecl ( ) /* error, how can I define __cdecl as 'nothing" here? */
#endif
#include <boost/dll/import.hpp>
boost::dll::shared_library lib;
unsigned long device_count(char* pid) {
typedef unsigned long(__cdecl func_sig)(char *pvid_id);
return lib.get<func_sig>("DLL_Symbol")(pid);
}
#define __cdecl
Couldn't be simpler! Or better, to limit the spreading of implementation-reserved identifiers:
#if BOOST_OS_WINDOWS
#define YOURLIB_CDECL __cdecl
#else
#define YOURLIB_CDECL /* nothing */
#endif
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!
First of all I am using Mingw 4.8 as the compiler of the C++ DLL in Code:blocks 13.12 and Lazarus 1.4.2 for working with the pascal code.(windows 7)
I need to generete a dll in c++ or c that can be called from a pascal program.
The problem is that my knowlegde about pascal is null, It dosn't look really complicate to make a simple program but I can't find good information about how to import and use a C/C++ DLL.
The only thing that moreless worked was this: http://www.drbob42.com/delphi/headconv.htm
My real code:
Pascal:
funtion hello():Integer; external 'function' index 1;
...
Label1.Caption:=IntToStr(hello());
C++ DLL header:
#ifndef function_H
#define function_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BUILDING_DLL
#define FUNCTION_DLL __declspec(dllexport)
#else
#define FUNCTION_DLL __declspec(dllimport)
#endif
int __stdcall FUNCTION_DLL hello( );
#ifdef __cplusplus
}
#endif
#endif
C++ file:
#include <stdio.h>
#include "function.h"
__stdcall int hello( )
{
return 8;
}
But when try to pass any argument or do something complicated with the function,starts to give randoms numbers.
This is the new code:
Pascal:
function function1(t1:Integer):Integer; external 'function' index 1;
...
entero:=8;
Label1.Caption:=IntToStr(function1(entero2));
Also I update the c++ code to this:
C++:
#include <stdio.h>
#include "function.h"
__stdcall int function1(int t1)
{
return t1*2;
}
Header:
#ifndef funtion_H
#define funtion_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BUILDING_DLL
#define FUNCTION_DLL __declspec(dllexport)
#else
#define FUNCTION_DLL __declspec(dllimport)
#endif
int __stdcall FUNCTION_DLL function1(int t1);
#ifdef __cplusplus
}
#endif
#endif
I aslo read this other info:http://www.jrsoftware.org/ishelp/index.php?topic=scriptdll. And tried to implement the dll call like this:
Pascal:
function function1(t1: Integer): Integer; external 'function1#files:function.dll';
But I receive an error saying that:
The procedure entry point function1 could not be located in the
dynamic link library function.dll
I'm looking for an example that works or a online tutorial or something to continue working because I am very stuck with this.
Thank you in advance.
You need to make the calling conventions match. Your C++ code uses __stdcall. The Pascal code does not specify a calling convention and so defaults to register.
Declare the Pascal import like this:
function function1(t1:Integer):Integer; stdcall; external 'function' index 1;
Are you quite sure that you need to use an index when importing? It is much more common to import by name than by ordinal. I'd expect to see the import looking like this:
function function1(t1:Integer):Integer; stdcall; external 'function';
The reason why the function with no parameters succeeds is that for a parameterless function, the differences between calling convention do not matter. Once you start passing an argument, stdcall means that the argument is passed via the stack, and register means it is passed in a register. This mismatch explains the behaviour you observe.
I am a newbie to disk-based R-trees although I have coded main memory based R-Trees. In order to understand disk based R-Trees I am using the library "libspatialIndex". While understanding the library I am coming across strange definitions of classes like the one given below:
class SIDX_DLL IStorageManager
{
public:
virtual void loadByteArray(const id_type id, uint32_t& len, byte** data) = 0;
virtual void storeByteArray(id_type& id, const uint32_t len, const byte* const data) = 0;
virtual void deleteByteArray(const id_type id) = 0;
virtual ~IStorageManager() {}
}; // IStorageManager
I fail to understand this new definition of class whereby it uses SIDX_DLL in the class definition. Can someone please give me pointers as to what does SIDX_DLL represent in the class definition.
It's a macro that allows the same include be used from library clients and library implementation. Add attributes required to implement dynamic linking.
Tools.h
47 #if defined _WIN32 || defined _WIN64 || defined WIN32 || defined WIN64
48 #ifdef SPATIALINDEX_CREATE_DLL
49 #define SIDX_DLL __declspec(dllexport)
50 #else
51 #define SIDX_DLL __declspec(dllimport)
52 #endif
53 #else
54 #define SIDX_DLL
55 #endif
That's just a macro, which adds compiler-specific attributes to class definition
SIDX_DLL is a macro. It's for making the IStorageManager symbol exported in a dll.
This kind of macros are usually defined like this:
#if defined(_MSC_VER) && defined(SIDX_EXPORTS)
# define SIDX_DLL __declspec(dllexport)
#elif defined(_MSC_VER)
# define SIDX_DLL __declspec(dllimport)
#else
# define SIDX_DLL
#endif
SIDX_EXPORTS is a MSVC-defined symbol that only gets defined when compiling the SIDX dll. In that case, SIDX_DLL expands to __declspec(dllexport). In all other cases, it expands to __declspec(dllimport) — which imports the symbol to wherever it is used.
The empty SIDX_DLL (the last #else in the listing) is for non-Windows environments.
It's define. You can read about this at http://libspatialindex.github.com/doxygen/Tools_8h_source.html 54 row.
It's a macro. It probably defines the dll import/export properties.
Go to its definition (F12), and you'll see that it is defined to __declspec(import) and __declspec(export)
I saw in the definition of a socket in msdn the following:
SOCKET WSAAPI socket(
__in int af,
__in int type,
__in int protocol
);
What is the prefix "__in" mean?
and what is WSAAPI ?
__in (and friends) specify the intended use of each parameter, so that calls to that function may be mechanically checked.
See http://msdn.microsoft.com/en-us/library/aa383701(v=vs.85).aspx on how to activate the checking.
http://msdn.microsoft.com/en-us/library/ms235402.aspx describes the modern alternative.
WSAAPI expands to the calling convention used for the socket library functions. This ensures that the code for calls to the functions are generated correctly, even if the calling code is set to build with a different calling convention.
It is a preprocessor macro that is defined as nothing. The purpose is to declare the interface so that the user of the interface knows the purpose of function arguments (in terms of input/output parameters).
WSAAPI is the name for Microsoft's socket API. It is based on Berkeley sockets.
For those looking to find the calling convention so they can call WSAAPI functions from another language, WSAAPI is defined in Winsock2.h as:
#define WSAAPI FAR PASCAL
Then in minwindef.h:
#define FAR far
#define far
#if (!defined(_MAC)) && ((_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED))
#define pascal __stdcall
#else
#define pascal
#endif
#ifdef _MAC
#ifdef _68K_
#define PASCAL __pascal
#else
#define PASCAL
#endif
#elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define PASCAL __stdcall
#else
#define PASCAL pascal
#endif
An _MSC_VER of 800 is Visual C++ 1.0, which is ancient.
So it looks like if you're writing Mac code and _68K_ is defined, you get the __pascal calling convention. If you're using Visual C++ >= 1.0 and developing for Windows, it's the __stdcall calling convention. Otherwise, it's either __stdcall or nothing, depending on whether _STDCALL_SUPPORTED is defined.
So basically WSAAPI probably evaluates to __stdcall on your machine.