En C ++, hacer funciones variadic (los que tienen ... al final de la lista de parámetros) necesariamente seguir la convención de llamada __cdecl?

StackOverflow https://stackoverflow.com/questions/2512746

Pregunta

Yo sé que __stdcall funciones no pueden tener elipses, pero quiero estar seguro de que no hay plataformas que soportan las funciones stdarg.h de convenciones de llamada que no sean __cdecl o __stdcall.

¿Fue útil?

Solución

La convención de llamada tiene que ser uno en que la persona que llama borra los argumentos de la pila (debido a que el abonado llamado no sabe lo que va a ser transmitida).

Esto no se corresponde necesariamente con lo que Microsoft llama "__cdecl" sin embargo. Sólo por ejemplo, en una SPARC, que va normalmente pasan los argumentos en los registros, porque así es como el SPARC está diseñado para trabajar - sus registros actúan básicamente como una pila de llamadas que se derrama a la memoria principal si las llamadas que reciben suficiente profundidad que no caben en el registro más.

A pesar de que estoy menos seguro de ello, yo esperaría más o menos la misma en IA64 (Itanium) - también tiene un gran conjunto de registros (un par de cientos, si no recuerdo mal). Si no me equivoco, que es un poco más permisiva sobre cómo utiliza los registros, pero yo esperaría que sea utilizado de manera similar, al menos, una gran parte del tiempo.

¿Por qué es importante para usted? El punto de usar stdarg.h y sus macros es que las diferencias se esconden en convención de llamada desde el código, por lo que puede trabajar con argumentos variables de forma portátil.

Editar, basado en los comentarios: Muy bien, ahora entiendo lo que está haciendo (al menos lo suficiente para mejorar la respuesta). Teniendo en cuenta que ya (al parecer) tiene código para manejar las variaciones en el ABI defecto, las cosas son más simples. Que sólo deja a la cuestión de si las funciones variadic siempre usan el "default ABI", lo que pasa a ser para la plataforma en cuestión. Con "stdcall" y "por defecto", como las únicas opciones, creo que la respuesta es sí. Sólo por ejemplo, en Windows, wsprintf y wprintf rompen la regla de oro, y los usos CDECL convención de llamada en lugar de stdcall.

Otros consejos

La forma más definitiva que se puede determinar esto es analizar las convenciones de llamada. Para las funciones variadic al trabajo, el convenio de llamada necesita un par de atributos:

  • El destinatario de la llamada debe ser capaz de acceder a los parámetros que no son parte de la lista de argumentos variable a partir de un desplazamiento fijo de la parte superior de la pila. Esto requiere que el compilador empujar los parámetros en la pila de derecha a izquierda. (Esto incluye cosas tales como el primer parámetro para printf, la especificación del formato. Además, la dirección de la lista de argumentos variable misma también debe derivarse de una ubicación conocida.)
  • La persona que llama debe ser responsable de la eliminación de los parámetros de la pila una vez que ha regresado a la función, porque sólo el compilador, al generar el código para la persona que llama, sabe cuántos parámetros se inserta en la pila en el primer lugar. La misma función variadic no tiene esta información.

stdcall no funcionará porque el destinatario de la llamada es responsable de hacer estallar los parámetros de la pila. En los viejos tiempos de Windows de 16 bits, pascal no funcionaría, ya que empujó parámetros en la pila de izquierda a derecha.

Por supuesto, como las otras respuestas han aludido, muchas plataformas no le otorga ninguna opción en términos de convención de llamada, lo que hace esta pregunta irrelevante para aquellos queridos.

Tenga en cuenta la siguiente función en un sistema x86:

vacío __stdcall algo (char *, ...);

La función se declara como __stdcall, que es una convención destinatario de la llamada-limpio. Pero una función variadic no puede ser destinatario de la llamada-limpia ya que el abonado llamado no sabe cuántos parámetros se pasó, por lo que no sabe cuántos se debe limpiar.

El compilador de Microsoft Visual Studio C / C ++ resuelve este conflicto mediante la conversión en silencio la convención de llamada a __cdecl, que es la convención de llamada variadic solo para funciones que no tienen un escondido este parámetro.

¿Por qué esta conversión tenga lugar en silencio en lugar de generar un aviso o error?

Mi conjetura es que es para hacer las opciones del compilador / GR (por defecto conjunto convención de llamada a __fastcall) y / Gz (por defecto conjunto convención de llamada a __stdcall) menos molesto.

Conversión automática de funciones variadic a __cdecl medios que usted puede añadir el / GR / o modificador de línea de comandos Gz a sus opciones de compilación, y todo seguirá siendo compilar y ejecutar (solo con la nueva convención de llamada).

Otra forma de ver esto no es por el pensamiento del compilador como conversión variadic __stdcall a __cdecl sino simplemente diciendo “para las funciones variadic, __stdcall es la persona que llama-limpio.”

clic aquí

¿Se refiere a 'las plataformas soportadas por MSVC 'o como regla general? Incluso si se confine a las plataformas soportadas por MSVC, todavía tiene situaciones como AMD64 donde no es sólo 'una' convención de llamada, y que el convenio de llamada se llama __stdcall, pero ciertamente no es la misma __stdcall se obtiene en x86.

Que yo sepa, la diversidad de las convenciones de llamada es única para DOS / Windows en x86. La mayoría de las otras plataformas tenían compiladores vienen con el sistema operativo y estandarizar la convención.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top