Sé que las funciones __stdcall no pueden tener elipsis, pero quiero asegurarme de que no haya plataformas que admitan las funciones stdarg.h para las convenciones de llamadas que no sean __cdecl o __stdcall.En C++, ¿las funciones variadas (aquellas con ... al final de la lista de parámetros) necesariamente siguen la convención de llamadas __cdecl?
Respuesta
La convención de llamadas tiene que ser aquella en la que el que llama borre los argumentos de la pila (porque el destinatario no sabe qué se pasará).
Eso no se corresponde necesariamente con lo que Microsoft llama "__cdecl". Solo por ejemplo, en un SPARC, normalmente pasará los argumentos en los registros, porque así es como el SPARC está diseñado para funcionar: sus registros básicamente actúan como una pila de llamadas que se propaga a la memoria principal si las llamadas son lo suficientemente profundas como para que ya no encajarán en el registro.
Aunque estoy menos seguro al respecto, esperaría más o menos lo mismo en IA64 (Itanium); también tiene un gran conjunto de registros (un par de cientos si la memoria sirve). Si no me equivoco, es un poco más permisivo sobre cómo usar los registros, pero espero que se use de manera similar al menos una gran parte del tiempo.
¿Por qué es esto importante para usted? El objetivo de usar stdarg.h y sus macros es ocultar las diferencias en la convención de llamadas de su código, por lo que puede funcionar con argumentos de variables de forma portátil.
Editar, basado en comentarios: Bien, ahora entiendo lo que estás haciendo (al menos lo suficiente para mejorar la respuesta). Dado que ya (aparentemente) tiene un código para manejar las variaciones en el ABI predeterminado, las cosas son más simples. Eso solo deja la cuestión de si las funciones variadic siempre usan el "ABI predeterminado", sea lo que sea que sea para la plataforma en cuestión. Con "stdcall" y "default" como las únicas opciones, creo que la respuesta es sí. Solo por ejemplo, en Windows, wsprintf
y wprintf
rompa la regla de oro, y usa la convención de llamadas cdecl en lugar de stdcall.
Se refiere a "plataformas compatibles con MSVC" o, como regla general, incluso si se limita a las plataformas admitidas por MSVC, todavía tiene situaciones como IA64 y AMD64 donde solo hay "una" convención de llamadas, y esa convención de llamadas se llama __stdcall
, pero ciertamente no es la misma __stdcall
que obtiene en x86.
AFAIK, la diversidad de convenciones de llamadas es exclusiva de DOS/Windows en x86. La mayoría de las otras plataformas tenían compiladores que vienen con OS y estandarizan la convención.
La manera más definitiva que puede determinar esto es analizar la llamada g convenciones. Para las funciones de variadic funcionan, 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 inserte los parámetros en la pila de derecha a izquierda. (Esto incluye cosas tales como el primer parámetro a
printf
, la especificación de formato. Además, la dirección de la lista de argumentos de variables también debe derivarse de una ubicación conocida.) - El llamante debe ser responsable de eliminar los parámetros del apilar una vez que la función ha regresado, porque solo el compilador, al generar el código para la persona que llama, sabe cuántos parámetros se insertaron en la pila en primer lugar. La función variadic en sí no tiene esta información.
stdcall
no funcionará porque el destinatario es responsable de sacar los parámetros de la pila. En los viejos días de Windows de 16 bits, pascal
no funcionaba porque empujaba los parámetros a la pila de izquierda a derecha.
Por supuesto, como han aludido las otras respuestas, muchas plataformas no le dan ninguna opción en términos de convención de llamadas, haciendo que esta pregunta sea irrelevante para esas.
considera la siguiente función en un sistema x86:
vacío algo __stdcall (char *, ...);
La función se declara como __stdcall, que es una convención de limpieza de llamada. Pero una función variadica no puede ser llamada-limpia, ya que el destinatario no sabe cuántos parámetros se pasaron, por lo que no sabe cuántos debe limpiar.
El compilador de Microsoft Visual Studio C/C++ resuelve este conflicto convirtiendo silenciosamente la convención de llamadas a __cdecl, que es la única convención de llamadas variadic admitida para funciones que no tienen un parámetro oculto.
¿Por qué esta conversión se lleva a cabo de forma silenciosa en lugar de generar una advertencia o error?
Supongo que es para hacer que las opciones del compilador/Gr (establezca la convención de llamadas predeterminada para __fastcall) y/Gz (establezca la convención de llamadas predeterminada para __stdcall) sean menos molestas.
La conversión automática de funciones variadic a __cdecl significa que puede simplemente agregar el modificador de línea/Gr o/Gz a sus opciones de compilación, y todo se compilará y ejecutará (solo con la nueva convención de llamadas).
Otra forma de ver esto no es por el pensamiento del compilador como convertir __stdcall variadic a __cdecl sino simplemente diciendo “para las funciones variadic, __stdcall es la persona que llama-limpio.”
- 1. ¿Por qué las funciones de subprocesos deben declararse como '__cdecl'?
- 2. __cdecl o __stdcall en Windows?
- 3. RhinoMocks - Obtención de parámetros de las funciones llamadas
- 4. ¿Cómo encontrar la convención de llamadas de un tercero dll?
- 5. ¡La composición de las funciones en una lista de funciones!
- 6. Poner coma (,) al final de la matriz. ¿Es una convención?
- 7. ¿Puedo deducir programáticamente la convención de llamadas utilizada por un dll de C++?
- 8. ¿Por qué la persona que llama debe borrar la pila en la convención de llamadas cdecl?
- 9. jQuery anexar al final de la lista
- 10. Revisiones repetidas de parámetros en las funciones
- 11. Funciones variadas de Scala y Seq
- 12. Cómo forzar la convención de llamadas cdecl para las funciones declaradas en el archivo de encabezado específico
- 13. de llamadas en la post-construida con parámetros
- 14. ¿Las bibliotecas de Scala siguen la misma convención de dominio invertido para nombrar paquetes como Java?
- 15. ¿Cómo usar el atributo de formato printf de GCC con las plantillas variadas de C++ 11?
- 16. lista de llamadas de la función usando la lista de comprensión
- 17. Ir al final de la función C++ en Vim
- 18. Depuración en javascript en vivo mediante la grabación de llamadas a funciones y parámetros
- 19. funciones dentro de las funciones en C
- 20. reproducir una lista de funciones y parámetros
- 21. Internet Explorer elimina la extensión .exe de la descarga cuando lo siguen los parámetros de URL
- 22. Comprender el prólogo llamada a la función C con __cdecl en las ventanas
- 23. GCC: ¿Es posible desactivar la advertencia "coma al final de la lista de enumeradores" cuando se usa -pedantic?
- 24. Error al verificar muchas llamadas a funciones
- 25. Extrayendo la lista de llamadas de funciones de DOxygen XML Output
- 26. Puntero de función y convención de llamadas
- 27. Declaraciones múltiples de funciones C++ con parámetros predeterminados
- 28. Nombre de la convención de nomenclatura stdlib de C/C++?
- 29. jQuery mover elemento de la lista al final de la lista
- 30. ¿Cuál es la necesidad de tener parámetros "nmem" y "tamaño" en las funciones C?
Su comentario sobre SPARC se aplica a muchas, si no a todas, las arquitecturas RISC. Dado que los registros son tan abundantes, el compilador solo los usa para pasar argumentos. Sin mencionar, son un poco más rápidos que la memoria, especialmente. ya que probablemente esté pasando datos que ya están en registros (aunque supongo que tendrá que insertarlos en la pila para restaurarlos si los necesita más adelante, pero ...). De todos modos, sé que así es como funciona en MIPS y estoy bastante seguro de que PPC funciona de la misma manera. –
* "¿Por qué te importa esto?" * Ben está trabajando en js-ctypes para Mozilla. Puede ver el contexto exacto en https://bugzilla.mozilla.org/show_bug.cgi?id=554790 (busque "idea loca") y puede encontrar algunos documentos que explican js-ctypes en https: //developer.mozilla. org/es/JavaScript_code_modules/ctypes.jsm –
No hace falta decir que js-ctypes solo está disponible para el código de aplicación y complementos, no para las páginas web. –