2012-06-29 19 views
6

Como sé, la convención de llamadas depende del compilador y de la arquitectura. Pero, ¿hay alguna diferencia clara entre las convenciones de llamadas C y C++?¿Cuáles son las diferencias entre las convenciones de llamadas C y C++?

+0

Por favor marque esta primera: [Stackoverflow] [1] [1]: http://stackoverflow.com/questions/949862/what-are-the-different-calling-conventions-in- cc-and-what-do-each-mean – Saif

+0

@Saif Sí, lo vi antes. Pero esa pregunta es acerca de las convenciones de llamada en compiladores C/C++. No sobre las diferencias entre la convención de llamadas C y la convención de llamadas C++. De todos modos, gracias – Kadiam

Respuesta

9

¿Pero hay alguna diferencia clara entre las convenciones de llamadas C y C++?

En general, no hay ninguno. C++ fue diseñado intencionalmente para ser lo más compatible posible con C, y en particular utiliza la interfaz binaria de la aplicación C en todos los sistemas.

Pero el C ABI no satisface una gran cantidad de características que necesita C++ (en particular, sobrecarga, espacios de nombres y plantillas de funciones), por lo que el compilador C++ realiza algunos cambios en los nombres de las funciones. Esto se llama name mangling

Así que para que las llamadas a funciones entre C y C++ código para trabajar, tales funciones deben ser declarados como extern "C" que deshabilita nombre mangling y se asegura de que las convenciones de llamada son los esperados por C (pero espero que este último aspecto es automático, aunque el estándar no lo exige).

C++ también tiene convenciones de llamada adicionales para funciones miembro (a veces llamados thiscall) que no existen en C. Pero funciones gratuitas utilizar la misma convención de llamada como C, el valor que está en un sistema dado.

+4

No he visto nada en ninguna parte que garantice nada de lo que se dice aquí. La única convención de llamadas en C++ que es lo mismo que C son funciones declaradas como extern "C". Pero he sabido que estoy equivocado antes. Si tiene una referencia sería genial. –

+2

@LokiAstari Hay varios libros de Bjarne Stroustrup que dicen exactamente eso. – EJP

+0

Si bien C++ se ha diseñado para que sea posible reutilizar la convención de llamadas C para lo que se comparte, la única manera de estar seguro es usar la opción "C" y me sorprendería que ningún compilador haya aprovechado la ventaja de visión para solucionar problemas con una convención de llamadas C anterior. – AProgrammer

2

Toda la noción de las diferentes convenciones de llamada entre idiomas va más allá de cualquier idioma (y sus especificaciones). Y así es como debería ser, esas cosas no tienen importancia para la especificación de ningún idioma que valga su nombre. Básicamente, tienes razón, está en el dominio de una implementación específica de una especificación de la arquitectura del compilador. Claro, algunas nociones discutidas en la especificación/estándar de un lenguaje dado como especificación de vinculación pueden afectar la convención de llamadas, pero no es una consecuencia planificada.

deber de ABI es estandarizar/formalizar estos conceptos que, por otra parte, las personas no tienen el deber de respetar (y probablemente debido a que la paleta de colores de las implementaciones varía un poco)

En realidad, la especificación debe ser ajeno a cómo se transmiten los parámetros, ya sea terminando en la pila o registros, una combinación de ambos, orden de asignación, etc. Ese es el trabajo de los muchachos que trabajan en la implementación y las personas que diseñan el hardware real, más importante aún, la instrucción conjuntos.

Por lo tanto: Ni C ni C++, como estandarizados, tienen algo que decir sobre cómo se implementan las cosas. Por lo tanto, no debe haber ninguna diferencia inherente a los idiomas. Solo en la forma en que se aplican. Y ese es el campo de la arquitectura del compilador.

+0

gracias @Domagoj Pero, ¿qué hay de la manipulación de nombres? ¿Está cambiando el nombre de una diferencia entre las convenciones de llamadas de C y C++? – Kadiam

+0

@Kasnel Se deriva de C, bueno, parcialmente (ha habido mucho tiempo para evolucionar, por lo que las cualificaciones deben emplearse). También está estandarizado por la interfaz binaria de la aplicación. Y básicamente no hay diferencia. Por lo general, cambia a medida que los compiladores necesitan introducir cosas nuevas, el cambio de nombre ha existido por mucho tiempo y no hay necesidad de arreglar lo que no se rompe. –

4

Como sé, la convención de llamadas depende del compilador y de la arquitectura.

Sí.

¿Pero hay alguna diferencia clara entre las convenciones de llamadas C y C++?

La mejor pregunta es "¿Hay similitudes?"

Sí:

Una función declarada extern "C" dentro de una aplicación C++ tiene la misma convención de llamada utilizado por una función de C en la que la arquitectura

Cualesquiera otros supuestos que tome acerca de convenciones de llamada son especulativas y pueden suceder. para ser el mismo, pero debe preocuparse por eso en una base de caso por caso.

5

No hay nada en ninguno de los estándares que requiera que las convenciones de llamadas C y C++ sean las mismas en un compilador dado, que no sea un C++ función declarada extern "C" n obligatoriamente debe invocarse con la misma convención de llamadas que una función C.

Es por eso que un puntero a función y un puntero-a-función-con-vinculación-C con los mismos parámetros y tipo de retorno, tienen diferentes tipos. Cuando se llama a la función, el compilador puede saber del tipo con el que se llama a la convención para llamar, si son diferentes.

En la práctica, no creo que haya tratado a sabiendas un ejemplo que utiliza una convención de llamadas incompatibles entre funciones libres con y sin enlace C. Por lo general, una implementación de C++ adopta su convención de llamadas del ABI del sistema en el que planea ejecutarse, para producir objetos enlazables (ejecutables y bibliotecas) que otros usuarios del sistema pueden entender en términos de ABI.

Esto no es obligatorio: a la norma no le importa si hay o no un sistema ABI, y al sistema generalmente no le importa cómo se realizan las llamadas dentro de un archivo ejecutable autocontenido [*]. Es sensato hacerlo a menos que exista alguna razón extraordinaria para no hacerlo. El sistema ABI en un sistema dado puede o no mencionar a C++; si no, entonces la implementación de C++ es por sí misma en lo que respecta a las funciones sin vinculación C, pero como digo es usualmente sensato hacer funciones que podría tener un enlace C usar la misma convención de llamadas como si tuvieran un enlace C.

Digo "incompatible" en lugar de "diferente", porque, por supuesto, hay algunas cosas que no se mencionan en la convención de llamadas C pero que deben especificarse en la convención de llamadas de C++. Cómo pasar una función de puntero a miembro, por ejemplo. Es muy posible que esto sea no fijado por el sistema ABI, y así queda en la implementación de C++. La razón para esto es dejar la implementación de la función de puntero a miembro hasta la implementación de C++, en lugar de que el sistema ABI haga algo que el fabricante considere que es el trabajo de un escritor de compiladores de C++.

Con la convención de llamadas fuera del camino, tenga en cuenta que el nombre de la creación de un mazo inevitablemente es diferente entre una función libre con o sin vinculación C. La razón es que el manchado de nombres de C++ debe incluir los tipos de los parámetros (debido a la sobrecarga de funciones), mientras que el mangle de nombres de C no debe (debido a las declaraciones de funciones externas con parámetros no especificados).

[*] Aunque he visto ejemplos en los que el uso de la convención de llamadas "incorrectas" rompe las cosas. ISTR es un dispositivo móvil de Windows donde si formateó la pila de forma diferente a lo que esperaba el sistema operativo, entonces ciertas excepciones de hardware eliminarían el dispositivo porque el sistema operativo intentó volver sobre la pila del hilo ofensivo y no pudo. Al menos en esa versión del sistema operativo, probablemente alrededor de 2005, si quería que los diagnósticos del sistema operativo funcionaran, tenía que usar las convenciones de llamadas de Windows internamente. O de todos modos la parte de la convención de llamadas relacionada con el formato de marco de pila. Esto fue totalmente nuestro error, por supuesto, pero no sé si pudimos haberlo arreglado correctamente al instalar nuestros propios controladores para las excepciones de hardware, en lugar de trabajar en torno a ellos al no causar las excepciones en primer lugar.Significaba que un proceso en modo de usuario podría trivialmente tomar el sistema operativo con una sobrecarga de pila, y también que era más difícil depurar nuestro código que en otros Windows. Así que culpamos ligeramente al sistema operativo.

1

No C o C++ estándar define un ABI. Esta es una decisión de diseño intencional que permite a los escritores de compiladores la libertad de crear una implementación lo más eficiente posible.

Con el tiempo, una convención de llamadas C llamada cdecl se ha convertido en el estándar de facto de las arquitecturas x86. De hecho, hay standards de-facto para el código C que se ejecuta en las máquinas AMD64, pero difieren entre los sistemas operativos UNIX y Windows.

En las máquinas Unix, hay un cierto movimiento hacia un ABI común de C++ basado en el Itanium C++ ABI publicado por Intel. Sin embargo, debido a la complejidad adicional de C++, diferentes versions del mismo compilador e incluso different compiler switches a menudo producen códigos de máquina que se ajustan a los ABI incompatibles.

El uso de extern "C" { ... } a menudo se puede confiar para obligar a un compilador a implementar una función utilizando el C ABI de facto, pero incluso esto no es requerido por el estándar de C++.

Si está interesado en una descripción exhaustiva de los ABI actuales de C++, entonces debe consultar el "Calling conventions for different C++ compilers and operating systems" de Agner Fog.

Cuestiones relacionadas