4

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?

Mengfan Ma
  • 351
  • 2
  • 13
  • 1
    The *compiler* treats the `__cdecl` declarations. It’s not (and cannot be) defined in the language, hence the macro is empty. – Konrad Rudolph Mar 29 '17 at 14:56
  • See that `#if` and its condition? If that condition is true, then the compiler might have those as extended keywords. – Some programmer dude Mar 29 '17 at 14:56
  • 1
    The Microsoft compiler uses `__cdecl` as a calling convention. For other compilers it can be defined as nothing. – Bo Persson Mar 29 '17 at 14:57
  • The URL in this answer redirects to https://learn.microsoft.com/en-us/cpp/cpp/cdecl?redirectedfrom=MSDN&view=msvc-170 - but the edit queue was full and I couldn't update it. – AJM Nov 07 '22 at 17:47
  • 32-bit code has multiple calling conventions, __stdcall is another common one. You found the 64-bit definition of it, x64 was a clean design that no longer distinguishes between cdecl and stdcall. So that's why the #define is empty. – Hans Passant Feb 09 '23 at 11:55

2 Answers2

1

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.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I see. So it's a way to comment `__cdecl` under certain conditions. But I'm still confused with the `#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)` line, what does it mean? – Mengfan Ma Mar 30 '17 at 02:30
  • 1
    @Mark: `_MSC_VER` is only defined by the Microsoft Visual C compiler, and contains its version number. This is a check if compilation is done on the Microsoft compiler (Version 8 or later), or a compiler declaring `_STDCALL_SUPPORTED`. They will use `__stdcall` and `__cdecl`; other compilers won't. – DevSolar Mar 30 '17 at 07:44
0

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)

peedurrr
  • 187
  • 16