¿Pueden lanzarse las funciones de C++ marcadas como Extern “C”?

5 minutos de lectura

avatar de usuario
Will Brode

Tengo funciones de C++ que quiero declarar usando extern "C" a pesar de que solo se llaman en código C++. Sí, sé que esto es extraño, pero es algo que me gustaría hacer por coherencia, ya que tenemos declaraciones mixtas de C y C++. Solo quiero asegurarme de que declarar una función de C++ como extern "C" no afectará el comportamiento de lanzamiento.

Se vería algo como esto:

extern "C" void foo() {throw exception;}

int bar()
{
    try
    {
        foo();
    } catch (exception e) { return 1; }
}

  • Pregunta relacionada.

    – Alexei Frunze

    6 de abril de 2013 a las 0:38


  • Las respuestas afirman que está invocando un comportamiento indefinido si se lanza una excepción desde el código C++ al código C real (que no sabría qué hacer con una excepción). Creo que es correcto, pero ¿está preguntando acerca de llamar al extern "C" funciones de C++ o de C? Si los está llamando desde C++ (y nunca desde C), existe la pregunta inevitable “¿por qué las funciones extern "C" si nunca se llaman desde otro idioma?”, pero creo que simplemente llamando a las funciones de C++ con extern "C" de C ++ significa que no se cruzan los límites del idioma y, por lo tanto, no hay un comportamiento indefinido.

    –Jonathan Leffler

    6 de abril de 2013 a las 0:49

  • Gracias a todos los que contribuyeron a responder esto. Si entiendo correctamente, la respuesta final a mi pregunta fue esta: la “C” externa no cambia la forma en que se maneja una excepción. Sin embargo, lanzar una excepción que no se detecta y cruza los límites del idioma tiene un comportamiento indefinido.

    – Will Brode

    09/04/2013 a las 18:05

  • q: “extern” C “no cambia la forma en que se maneja una excepción”: no leo las respuestas de esa manera. Específicamente /EHsc dice lo contrario.

    – Martín Ba

    1 de agosto de 2014 a las 19:48

  • @JonathanLeffler cada versión del compilador de cpp es otro idioma. Si tiene una biblioteca estática msvc, no funcionará con GCC a menos que sea una biblioteca C que use “C” externa. Cada compilador puede alterar los nombres como se sienten, por lo que termina con referencias indefinidas cuando la referencia realmente existe. Creo y no veo ninguna razón por la que la manipulación de nombres no deba estandarizarse; pero esta es una razón común para usar extern “C” solo para C++. Ejemplo, debo crear dll para usar el código de msvc en gcc ya que el código requiere cosas específicas de msvc. Entonces debo usar la “C” externa para suprimir la manipulación de nombres.

    – usuario13947194

    31 de agosto de 2021 a las 6:21

avatar de usuario
Nathan Ernst

“¿Pueden las funciones de C++ marcadas como Extern “C” lanzar?”

en el sentido de que ni el lenguaje ni el compilador te lo impedirán.

Noen el sentido de que si arroja, sería un comportamiento indefinido, ya que la excepción de C++ cruza los límites del idioma.

En la práctica: no lo hagas. Detecte la excepción y tradúzcala a un código de error, o un medio que el otro idioma pueda entender.

Así que el resultado final es: no haga lanzar una excepción de las funciones marcadas como extern "C".

  • no puedes decir YES cuando es undefined behavior. cuando invocas undefined behavior tu código está básicamente roto.

    – Martín York

    6 de abril de 2013 a las 3:44

  • @LokiAstari, se hizo la pregunta de si pueden lanzar, y la respuesta es sí. Si se invocó una función “C” externa directamente desde una función con enlace c++, no hay un comportamiento indefinido. Misma función invocada desde C, comportamiento indefinido. No hay necesariamente un cruce de idiomas solo por la vinculación, pero ciertamente es un olor.

    – Nathan Ernst

    08/04/2013 a las 23:48

  • @LokiAstari, debo hacer una excepción con su declaración, “No puedes decir YES cuando es undefined behaviour.” El “comportamiento indefinido” es indiferente a si puede o debe ocurrir. Solo especifica que el resultado no está definido. No especifica que nunca puede ocurrir. Las excepciones que cruzan los límites ocurren todo el tiempo. C++->C; C++ ->Java; C++->Python. La diferencia es que la mayoría de las bibliotecas de traducción de idiomas ofrecen una función para capturar, traducir y volver a generar excepciones en el idioma de destino.

    – Nathan Ernst

    9 de abril de 2013 a las 1:19

  • Tu primera suposición es incorrecta: If an extern "C" function was invoked directly from a function with c++ linkage. Si arroja su comportamiento indefinido. La ABI para una función C no contiene la información necesaria para permitir el despliegue de la pila.

    – Martín York

    9 de abril de 2013 a las 9:23

  • Tengo que estar de acuerdo con @LokiAstari. En mi código, tengo C++ llamando a extern c función que lanza una excepción, y es no ser atrapado (incluso con catch(...)). El compilador es el compilador Intel (icpc). Todo el código está escrito en C++, no hay C. La diferencia de vinculación parece ser suficiente para romper el despliegue de la pila.

    –Mark Lakata

    28/04/2015 a las 21:52


avatar de usuario
Martín Ba

Para GCC la respuesta no parece concluyente.

los Documentación MSVCsin embargo es relativamente claro sobre el tema:

  • /EHa y /EHsle dice al compilador que suponga que las funciones declaradas como “C” externa pueden generar una excepción.
  • /EHscle dice al compilador que asuma que las funciones declaradas como “C” externa nunca lanzan una excepción de C++

Entonces, para Visual-C ++, depende de las opciones del compilador si obtiene un comportamiento definido.

  • +1, pero te perdiste la respuesta de gcc en uno de los comentarios vinculados: -fexceptions. De los documentos de gcc: “… es posible que deba habilitar esta opción al compilar código C que necesita interoperar correctamente con controladores de excepción escritos en C ++”.

    – EML

    7 de enero de 2016 a las 17:28


se compilará pero es un comportamiento indefinido para lanzar desde la función marcada como con enlace C. C no tiene excepciones, por lo tanto, en general, solo debe devolver un código de error y/o proporcionar una función que devuelva la información sobre el último error.

#include <exception>
extern "C" void foo() {throw std::exception();}

compila bien

Aquí está la respuesta a su pregunta: http://yosefk.com/c++fqa/mixing.html#fqa-32.6

Básicamente no podrás atraparlo. (¿pero por qué no lo compilas y lo pruebas? :))

¿Ha sido útil esta solución?