¿Qué es __stdcall?


151

Estoy aprendiendo sobre la programación Win32, y el WinMainprototipo se ve así:

int WINAPI WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )

Estaba confundido sobre para qué era este WINAPIidentificador y encontré:

#define WINAPI      __stdcall

Que hace esto? Estoy confundido por tener algo en absoluto después de un tipo de retorno. Lo que es __stdcallpara? ¿Qué significa cuando hay algo entre el tipo de retorno y el nombre de la función?


2
@AndrewProck El cambio "ficticio" estuvo bien en este caso, pero en general puede usar  s para evitar el mínimo de 6 caracteres tonto (y contraproducente - caso en punto).
Adi Inbar

Respuestas:


170

__stdcalles la convención de llamada utilizada para la función. Esto le dice al compilador las reglas que se aplican para configurar la pila, generar argumentos y obtener un valor de retorno.

Hay una serie de otras convenciones de llamada, __cdecl, __thiscall, __fastcally el maravillosamente nombrados __declspec(naked). __stdcalles la convención de llamadas estándar para las llamadas al sistema Win32.

Wikipedia cubre los detalles .

Principalmente importa cuando está llamando a una función fuera de su código (por ejemplo, una API del sistema operativo) o cuando el sistema operativo lo está llamando (como es el caso aquí con WinMain). Si el compilador no conoce la convención de llamada correcta, es probable que tenga bloqueos muy extraños ya que la pila no se administrará correctamente.


8
Consulte esta pregunta para ver un ejemplo de accidentes muy intensos stackoverflow.com/questions/696306/…
sharptooth

Si no me equivoco, estas convenciones de llamada controlan cómo el compilador produce el código de ensamblaje. Al interactuar con el código de ensamblaje, es fundamental que se tenga en cuenta la convención de llamada para evitar problemas de pila. Aquí hay una buena tabla que documenta algunas convenciones: msdn.microsoft.com/en-us/library/984x0h58.aspx
Nicholas Miller

¿Podemos decir que esto deshabilitaría ciertas optimizaciones ilegales?
kesari

40

C o C ++ en sí no definen esos identificadores. Son extensiones del compilador y representan ciertas convenciones de llamadas. Eso determina dónde colocar argumentos, en qué orden, dónde la función llamada encontrará la dirección de retorno, y así sucesivamente. Por ejemplo, __fastcall significa que los argumentos de las funciones se pasan sobre los registros.

El artículo de Wikipedia proporciona una visión general de las diferentes convenciones de llamadas que se encuentran por ahí.


18

Las respuestas hasta ahora han cubierto los detalles, pero si no tiene la intención de desplegarse al ensamblaje, todo lo que tiene que saber es que tanto la persona que llama como la persona que llama deben usar la misma convención de llamadas, de lo contrario obtendrá errores que Son difíciles de encontrar.


12

Estoy de acuerdo en que todas las respuestas hasta ahora son correctas, pero esta es la razón. Los compiladores C y C ++ de Microsoft proporcionan varias convenciones de llamadas para la velocidad (prevista) de las llamadas a funciones dentro de las funciones C y C ++ de una aplicación. En cada caso, la persona que llama y la persona que llama deben acordar qué convención de llamada utilizar. Ahora, Windows mismo proporciona funciones (API), y esas ya se han compilado, por lo que cuando las llame, debe cumplirlas. Cualquier llamada a las API de Windows y las devoluciones de llamada de las API de Windows deben usar la convención __stdcall.


3
y no debe confundirse con _standard_call en que es standard-c! uno podría pensar que ese sería el punto de __stdcall si no se conoce mejor
Johannes Schaub - litb

3
Un pequeño inconveniente: hay algunas API de Windows que usan __cdecl en lugar de __stdcall, generalmente las que toman un número variable de parámetros, como wsprintf ().
Michael Burr

Tienes razón. Se llama para parecerse a una función CRT pero es una API. ¿Por casualidad sabes cómo P / Invocarlo desde C #?
Programador de Windows el

No he probado esto, pero pinvoke.net da esta firma: "static extern int wsprintf ([Out] StringBuilder lpOut, string lpFmt, ...);"
Michael Burr el

Mi intuición dice que el compilador de C # no sabría usar la convención __cdecl en esa.
Programador de Windows el



4

__stdcall se usa para poner los argumentos de la función en la pila. Después de completar la función, automáticamente desasigna la memoria. Esto se usa para argumentos fijos.

void __stdcall fnname ( int, int* )
{
    ...
}

int main()
{
    CreateThread ( NULL, 0, fnname, int, int*...... )
}

Aquí el nombre fn tiene argumentos que empuja directamente a la pila.


1

Nunca tuve que usar esto antes hasta hoy. Es porque en mi código estoy usando subprocesos múltiples y la API de subprocesos múltiples que estoy usando es la de Windows (_beginthreadex).

Para comenzar el hilo:

_beginthreadex(NULL, 0, ExecuteCommand, currCommand, 0, 0);

La función ExecuteCommand DEBE usar la palabra clave __stdcall en la firma del método para que beginthreadex la llame:

unsigned int __stdcall Scene::ExecuteCommand(void* command)
{
    return system(static_cast<char*>(command));
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.