3

Before posting this question, I have already read some documentation, SO answers and watched some videos to understand __stdcall. So far I have understood that it's a calling convention and specifies to push parameters from right to left on the stack. This also signifies when to clear the stack.

But I am still not able to understand the advantage and cases where I should use __stdcall.

I have come across the following code, which is called when an OPC-UA client is closed. I see that this should follow the __stdcall calling convention but why? What may have happened if __stdcall was not specified for the following method?

OpcUa_StatusCode __stdcall opcua_client::onShutdownMessage(OpcUa_Handle hApplication, OpcUa_Handle hSession, OpcUa_String strShutdownMessage, void* extraParam)
{
    opcua_client* pOpcClient = NULL;
    if (extraParam)
    {
        try
        {
            pOpcClient = qobject_cast <opcua_client*>((QObject*)extraParam);
            throw(55);
        }
        catch (int exeption)
        {

        }
    }

    OpcUa_StatusCode uStatus = OpcUa_Good;

    QString strShutDownMsg = QString::fromUtf8(OpcUa_String_GetRawString(&strShutdownMessage));
    bool bOK;
    OpcUa_StatusCode uClientLibStatus = uClientLibStatus = strShutDownMsg.toUInt(&bOK, 16);

    if (pOpcClient)
    {
        if (uClientLibStatus > 0)
            pOpcClient->process_onShutdownMessage(uClientLibStatus);
    }
    else
    {
        return uStatus;
    }

    return uStatus;
}
skm
  • 5,015
  • 8
  • 43
  • 104
  • It is the standard calling convention for the operating system and COM libraries in 32-bit code. OPC is heavily COM-based, so expect to see a lot of stdcall around. Albeit that onShutdownMessage() is not one of the standard interface functions. Maybe you use a toolkit that dictates stdcall, not unusual at all. – Hans Passant Oct 10 '19 at 11:35

2 Answers2

3

Function calling convention must be followed by the caller. If it is there, then there must be some caller of this function that will assume it has to be called in a specific way. This is usually important when you have a callback function.

Other than that, stdcall is meant to reduce code size compared to cdecl by moving argument cleanup code from the caller to the callee (which can use ret imm16 on x86).

This is an old micro optimization for IA-32 architecture. MSVC accepts __stdcall keyword on other architectures too, but it doesn't do anything there.

Check this example:

__declspec(noinline) int sum(int a, int b)
{
    return a + b;
}

int add1(int a)
{
    return sum(a, 1);
}

MSVC compiles this to:

int sum(int,int) PROC
  mov eax, DWORD PTR _a$[esp-4]
  add eax, DWORD PTR _b$[esp-4]
  ret 0 ; this instruction will be replaced
int sum(int,int) ENDP

int add1(int) PROC
  push 1
  push DWORD PTR _a$[esp]
  call int sum(int,int)
  add esp, 8 ; this instruction will be removed
  ret 0
int add1(int) ENDP

And version with stdcall:

__declspec(noinline) int __stdcall sum(int a, int b)
{
    return a + b;
}

int add1(int a)
{
    return sum(a, 1);
}

which compiles to:

int sum(int,int) PROC
  mov eax, DWORD PTR _a$[esp-4]
  add eax, DWORD PTR _b$[esp-4]
  ret 8 ; 0 argument replaced with 8
int sum(int,int) ENDP

int add1(int) PROC
  push 1
  push DWORD PTR _a$[esp]
  call int sum(int,int)
  ret 0 ; extra instruction is missing here
int add1(int) ENDP

Notice how the 2nd example uses ret 8 and the caller doesn't have an additional add esp, 8.

2

opcua_client::onShutdownMessage looks like callback function. That is, a function that is sent to some API which calls the function at a later time. The callback function must then have the calling convention expected by the API, in this case __stdcall. Since __stdcall is the default calling convention on the Win32 platform, it does not have to be specified when building for Win32.

Pibben
  • 1,876
  • 14
  • 28