c++ c callback extern-c

¿Por qué necesita "extern C" para las devoluciones de llamada de C++ a las funciones de C?



callback extern-c (6)

Está claro que la función thread_proxy es privada interna y no creo que se dañe como "thread_proxy" porque en realidad no la necesito para nada.

En cualquier caso, todavía va a ser destrozado. (Si no hubiera sido extern "C" ) Así es como funciona el compilador. Estoy de acuerdo en que es posible que un compilador pueda decir "esto no necesariamente tiene que ser destrozado", pero el estándar no dice nada al respecto. Dicho esto, la mutilación no entra en juego aquí, ya que no estamos tratando de vincularnos a la función.

De hecho, en todo mi código que había escrito y que se ejecuta en muchas plataformas, nunca utilicé una extern "C" y esto funcionó tal cual con las funciones normales.

Escribir en diferentes plataformas no tiene nada que ver con extern "C" . Espero que todo el código estándar de C ++ funcione en todas las plataformas que tengan un compilador estándar compatible con C ++.

extern "C" tiene que ver con la interfaz con C, cuyo pthread es una biblioteca de. No solo no destroza el nombre, se asegura de que sea llamable con la convención de llamadas C. Es la convención de llamadas la que debe garantizarse, y como no podemos asumir que estamos ejecutando en un compilador, plataforma o arquitectura determinados, la mejor manera de intentarlo es con la funcionalidad que se nos brinda: extern "C" .

Mi problema es que las funciones extern "C" contaminan el espacio de nombres global y no están realmente ocultas como espera el autor.

No hay nada contaminante sobre el código anterior. Está en un espacio de nombres sin nombre, y no se puede acceder fuera de la unidad de traducción.

Encuentro tales ejemplos en el código Boost.

namespace boost { namespace { extern "C" void *thread_proxy(void *f) { .... } } // anonymous void thread::thread_start(...) { ... pthread_create(something,0,&thread_proxy,something_else); ... } } // boost

¿Por qué necesitas realmente esta extern "C" ?

Está claro que la función thread_proxy es privada interna y no creo que se dañe como "thread_proxy" porque en realidad no la necesito para nada.

De hecho, en todo mi código que había escrito y que se ejecuta en muchas plataformas, nunca utilicé una extern "C" y esto funcionó tal cual con las funciones normales.

¿Por qué se agrega extern "C" ?

Mi problema es que las funciones extern "C" contaminan el espacio de nombres global y no están realmente ocultas como espera el autor.

Esto no es un duplicado! No estoy hablando de destrozos y enlaces externos. ¡Es obvio en este código que el enlace externo no es deseado!

Respuesta: Las convenciones de llamada de las funciones C y C ++ no son necesariamente las mismas, por lo que necesita crear una con la convención de llamada C. Ver 7.5 (p4) del estándar C ++.


Dado que no se garantiza que C y C ++ tengan la misma convención de llamada, debe declarar la función de devolución de llamada como extern "C" para pasarla a la función pthread_create C.

La función thread_proxy anterior tiene un enlace externo (es decir, es visible fuera de su unidad de traducción) porque los espacios de nombres no tienen ningún impacto en las funciones extern "C" , incluso los espacios de nombres anónimos. En su lugar, para dar enlace interno a la función thread_proxy , debe declararlo como estático:

namespace boost { namespace { extern "C" { static void *thread_proxy(void *f) { .... } } // extern "C" } // anonymous ... } // boost

[Editar] Tenga en cuenta que el impulso ha incorporado este cambio. Consulte https://svn.boost.org/trac/boost/ticket/5170 .


La pregunta es válida: aunque la función se pasa a una biblioteca C, esa biblioteca C no se vincula al código C ++ en absoluto. Solo se le da la dirección de la función, por lo que no tiene ningún interés en absoluto en el nombre de la función.

El punto es que la extern "C" es lo más parecido a una forma multiplataforma de decirle al compilador que haga que la función use la convención de llamada estándar de C en esa plataforma (es decir, exactamente cómo se deben pasar los parámetros y los valores de retorno en la plataforma). apilar).

Es lamentable que también tenga el efecto secundario de crear un símbolo de enlace externo a nivel global. Pero esto podría mitigarse usando un nombre como boost_detail_thread_proxy en boost_detail_thread_proxy lugar.


Probablemente porque estás interconectando una biblioteca de C simple - pthreads.


Se está utilizando para hacer que la función use lo que sea que el compilador entienda por la convención de llamada de C y evite las palabras clave específicas del compilador, como __cdecl .

Eso es todo al respecto. No tiene absolutamente nada que ver con la manipulación de nombres, espacios de nombres o cualquiera de las otras respuestas extrañas aquí (como ya sabías cuando preguntaste).


extern "C" enlace extern "C" no significa necesariamente que solo se suprima la manipulación de nombres. De hecho, puede haber un compilador que trate la extern "C" como una convención de llamada diferente.

El estándar deja esto completamente abierto como semántica definida por la implementación.