2008-11-18 17 views
119

estoy aprendiendo acerca de la programación de Win32, y el prototipo WinMain parece:¿Qué es __stdcall?

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

que fue confundido en cuanto a lo que este identificador WINAPI fue y encontró:

#define WINAPI  __stdcall 

¿Qué hace esto? Estoy confundido por tener algo después de un tipo de devolución. ¿Para qué es __stdcall? ¿Qué significa cuando hay algo entre el tipo de devolución y el nombre de la función?

+1

@AndrewProck El "ficticia" El cambio fue correcto en este caso, pero en general puede usar ' ' s para evitar el mínimo de 6 caracteres (y contraproducente, por ejemplo). –

Respuesta

137

__stdcall es la convención de llamadas utilizada para la función. Esto le dice al compilador las reglas que se aplican para configurar la pila, empujar los argumentos y obtener un valor de retorno.

Hay una serie de otras convenciones de llamadas, __cdecl, __thiscall, __fastcall y la maravillosamente llamada __naked. __stdcall es la convención de llamadas estándar para llamadas al sistema Win32.

Wikipedia cubre details.

Principalmente importa cuando llama a una función fuera de su código (por ejemplo, una API de sistema operativo) o si 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 obtenga bloqueos muy extraños, ya que la pila no se gestionará correctamente.

+8

Consulte esta pregunta para ver un ejemplo de fallas de Starnge http://stackoverflow.com/questions/696306/run-time-check-failure-0-loading-queryfullprocessimagename-from-kernel32-dll – sharptooth

+0

Si no me equivoco, entonces estas convenciones de llamadas controlan cómo el compilador produce el código de ensamblaje. Al interactuar con el código de ensamblaje, es crítico que se tome nota de la convención de llamadas para evitar problemas de pila. Aquí hay una buena tabla que documenta algunas convenciones: https://msdn.microsoft.com/en-us/library/984x0h58.aspx –

+0

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

5

Tiene que ver con cómo se llama a la función, básicamente el orden en que las cosas se ponen en la pila y quién es responsable de la limpieza.

Aquí está la documentación, pero no significa mucho si no se entiende la primera parte:
http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx

31

C o C++ en sí no definen esos identificadores. Son extensiones de compilador y representan ciertas convenciones de llamadas. Eso determina dónde colocar los 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 por los registros.

El Wikipedia Article proporciona una descripción general de las diferentes convenciones de llamadas que se encuentran por ahí.

15

Las respuestas hasta ahora han cubierto los detalles, pero si no tiene la intención de bajar al montaje, todo lo que tiene que saber es que tanto la persona que llama como quien llama deben usar la misma convención de llamadas, de lo contrario ' Obtendré errores que son difíciles de encontrar.

9

Acepto 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 llamadas usar. Ahora, Windows mismo proporciona funciones (API), y esas ya han sido compiladas, por lo que cuando las llame debe cumplirlas. Todas las llamadas a las API de Windows y las devoluciones de llamadas de las API de Windows deben usar la convención __stdcall.

+2

y no se debe confundir con _standard_call en que es estándar-c! uno podría pensar que sería el punto de __stdcall si uno no sabe mejor –

+2

Un pequeño nitpick: 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(). –

+0

Tienes razón. Su nombre se parece a una función CRT, pero es una API. Por casualidad, ¿sabes cómo P/invocarlo desde C#? –

4

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

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

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

Aquí el fnname tiene argumentos que empujan directamente en la pantalla.

1

nunca tuve que usar esto antes hasta hoy. Es porque en mi código estoy usando multi-threadding y la API multi-threading que estoy usando es la de Windows (_beginthreadex).

Para iniciar el hilo:

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

La función ExecuteCommand MUST utilizar la palabra clave __stdcall en la firma del método con el fin de beginthreadex llamarlo:

unsigned int __stdcall Scene::ExecuteCommand(void* command) 
{ 
    return system(static_cast<char*>(command)); 
}