En C ++, ¿es seguro / portátil para usar el puntero de la función de miembro estático para las devoluciones de llamada C API? -- ++ campo con callback campo con portability camp Relacionados El problema

In C++, is it safe/portable to use static member function pointer for C API callbacks?


26
vote

problema

Español

En C ++, ¿es seguro / portátil para usar el puntero de la función de miembro estático para las devoluciones de llamada C API? ¿El ABI de una función de miembro estático es igual a una función C?

Original en ingles

In C++, is it safe/portable to use static member function pointer for C API callbacks? Is the ABI of a static member function the same as a C function?

        
 
 

Lista de respuestas

20
 
vote
vote
La mejor respuesta
 

No es seguro por el estándar C ++. Como se indica en esto, así que publica :

Una función de devolución de llamada C implementada en C ++ debe ser externa "C". Puede parecer que funciona como una función estática en una clase porque las funciones de clase-estáticas a menudo utilizan la misma convención de llamadas como una función C. Sin embargo, hacer eso es un error que está a la espera de suceder (vea los comentarios a continuación), por favor, no, pase por un envoltorio externo "C" en su lugar.

y de acuerdo con los comentarios hechos por Martin York en esa respuesta Hay problemas en el mundo real que intentan hacerlo en algunas plataformas.

Realice sus devoluciones de llamada C ABI extern "C" .


Editar: Agregar algunas cotizaciones de soporte de la norma (énfasis mina):

3.5 "Programa y enlace":

Después de todos los ajustes de los tipos (durante los cuales los TypedeFS (7.1.3) se reemplazan por sus definiciones), los tipos especificados por todas las declaraciones que se refieren a un objeto o función determinado serán idénticas , excepto que Las declaraciones para un objeto de matriz pueden especificar los tipos de matriz que difieren por la presencia o ausencia de una gran cantidad de matriz (8.3.4). Una violación de esta regla sobre la identidad de tipo no requiere un diagnóstico. [3.5 / 10]

[Nota: se puede lograr una enlace a las declaraciones que no C ++ usando una especificación de enlace (7.5). ] [3.5 / 11]

y

7.5 "Especificaciones de enlace":

... Dos tipos de funciones con diferentes vínculos de idioma son tipos distintos incluso si son idénticos. [7.5 / 1]

Por lo tanto, si el código que hace que la devolución de llamada está utilizando las enlaces de idioma C para la devolución de llamada, entonces el objetivo de devolución de llamada (en el programa C ++) también debe.

 

It is not safe per the C++ standard. As stated in this SO posting:

A C callback function implemented in C++ must be extern "C". It may seem to work as a static function in a class because class-static functions often use the same calling convention as a C function. However, doing that is a bug waiting to happen (see comments below), so please don't - go through an extern "C" wrapper instead.

And according to comments made by Martin York in that answer there are real-world problems trying to do so on some platforms.

Make your C ABI callbacks extern "C".


Edit: Adding some supporting quotes from the standard (emphasis mine):

3.5 "Program and linkage":

After all adjustments of types (during which typedefs (7.1.3) are replaced by their definitions), the types specified by all declarations referring to a given object or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound (8.3.4). A violation of this rule on type identity does not require a diagnostic. [3.5/10]

[Note: linkage to non-C++ declarations can be achieved using a linkage-specification (7.5). ] [3.5/11]

And

7.5 "Linkage specifications":

... Two function types with different language linkages are distinct types even if they are otherwise identical. [7.5/1]

So if the code making the callback is using C language bindings for the callback, then the callback target (in the C++ program) must as well.

 
 
         
         
6
 
vote

Después de buscar y varios descansos al atacar otros problemas, encontré una respuesta que es clara y sucinta (para estándar, de todos modos):

Llamando a una función a través de una expresión cuyo tipo de función tiene un enlace de idioma que es diferente de la conexión de idioma del tipo de función de la definición de la función llamada La definición no está definida. [5.2.2 / 1]

Todavía sostengo que es problemático a un nivel fundamental para usar el texto del estándar C ++ para definir el comportamiento de una biblioteca C compilada con un compilador C, y exactamente cómo funciona la interoperabilidad de INTERLANGAGE es muy específica de la implementación; Sin embargo, este es el más cercano, creo que cualquiera de los estándares puede (actualmente), la esperanza de definir dicha interacción.

En particular, este es un comportamiento indefinido (y no está usando una biblioteca C para que no surja ese problema):

  void call(void (*pf)()) { pf(); } // pf() is the UB extern "C" void f(); int main() { call(f); } // though I'm unsure if a diagnostic is required for call(f)   

comau ¿Dé un diagnóstico en call(f) (aunque puede hacer eso incluso Si no se requiere diagnóstico).

Esto no es un comportamiento indefinido, y muestra cómo incluir el enlace de idioma en un tipo de puntero de función (que es a través de un TypedeF):

  extern "C" typedef void F(); void call(F* pf) { pf(); } extern "C" void f(); int main() { call(f); }   

o podría ser escrito:

  extern "C" { typedef void F(); void f(); } void call(F* pf) { pf(); } int main() { call(f); }   
 

After searching and several breaks while attacking other problems, I found an answer which is clear and succinct (for standardese, anyway):

Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function's definition is undefined. [5.2.2/1]

I still maintain that it is problematic at a fundamental level to use text from the C++ standard to define the behavior of a C library compiled with a C compiler, and exactly how that interlanguage interoperability works is very implementation-specific; however, this is the closest I think either standard can (currently) hope to define such interaction.

In particular, this is undefined behavior (and isn't using a C library so that issue doesn't arise):

void call(void (*pf)()) { pf(); } // pf() is the UB extern "C" void f(); int main() { call(f); } // though I'm unsure if a diagnostic is required for call(f) 

Comeau does give a diagnostic at call(f) (though it can do that even if the diagnostic isn't required).

This isn't undefined behavior, and shows how to include language linkage in a function pointer type (which is through a typedef):

extern "C" typedef void F(); void call(F* pf) { pf(); } extern "C" void f(); int main() { call(f); } 

Or could be written:

extern "C" { typedef void F(); void f(); } void call(F* pf) { pf(); } int main() { call(f); } 
 
 
5
 
vote

Para todos los compiladores de Windows C ++ que conozco, la respuesta es sí, pero nada en el estándar de idioma garantiza esto. Sin embargo, no dejaría que eso lo detendría, es una forma muy común de implementar devoluciones de llamadas utilizando C ++, es posible que tenga que declarar las funciones estáticas como Winapi. Esto se toma de una antigua biblioteca de subprocesos de mi propia:

  class Thread {    ...    static DWORD WINAPI ThreadFunction( void * args ); };   

Donde este es el uso de devolución de llamada por TE Windows Threading API.

 

For all the Windows C++ compilers that I'm aware of, the answer is yes, but nothing in the language standard guarantees this. I wouldn't let that stop you however, it's a very common way of implementing callbacks using C++ - you may find you need to declare the static functions as WINAPI however. This is taken from an old threading library of my own:

class Thread {    ...    static DWORD WINAPI ThreadFunction( void * args ); }; 

where this is the callback use by te Windows threading API.

 
 
         
         
3
 
vote

ABI no está cubierto por los estándares C o C ++, a pesar de que C ++ le da "vínculo de idioma" a través de extern "C" . Por lo tanto, ABI es fundamentalmente compilador / plataforma específica. Ambos estándares dejan muchas, muchas cosas hasta la implementación, y esta es una de ellas.

En consecuencia, escribir un código 100% portátil o compiladores de conmutación, es difícil de imposible, pero permite a los proveedores y usuarios una flexibilidad considerable en sus productos específicos. Esta flexibilidad permite más programas de espacio y tiempo eficientes, de maneras que no tienen que anticiparse por adelantado por los comités de normas.


Como lo entiendo, las reglas de ISO no permiten un estándar más a menudo de una vez cada 10 años (pero pueden haber varias publicaciones, como TC1 y TR1 para C ++). Además, existe la idea (no estoy seguro de si esto proviene de ISO, se lleva a cabo del comité C, o incluso de otros lugares) a "destilar" / estandarizar la práctica existente en lugar de ir al campo izquierdo, y hay < EM> Muchos prácticas existentes, algunas de las cuales el conflicto.

 

ABI isn't covered by either the C or C++ standards, even though C++ does give you "language linkage" through extern "C". Therefore, ABI is fundamentally compiler/platform specific. Both standards leave many, many things up to the implementation, and this is one of them.

Consequently, writing 100% portable codexe2x80x94or switching compilersxe2x80x94is hard to impossible, but allows vendors and users considerable flexibility in their specific products. This flexibility allows more space and time efficient programs, in ways that don't have to be anticipated in advance by the standards committees.


As I understand it, ISO's rules do not allow a standard more often than once every 10 years (but there can be various publications, such as TC1 and TR1 for C++). Plus there is the idea (I'm not sure if this comes from ISO, is carried over from the C committee, or even from elsewhere) to "distill"/standardize existing practice rather than going off into left field, and there are many existing practices, some of which conflict.

 
 
         
         

Relacionados problema

2  Independencia de la base de datos en UNIX / C  ( Database independence in unix c ) 
Tenemos un sistema escrito en C y corriendo bajo Solaris & AMP; Linux que utiliza la Biblioteca Sybase CT para acceder a una base de datos SYBASE. Generamos l...

0  ¿Es posible crear dinámicamente equivalente de límites.H Macros durante la compilación?  ( Is it possible to dynamically create equivalent of limits h macros during compil ) 
La razón principal de esto es intentar escribir la biblioteca C perfectamente portátil. Después de unas semanas, terminé con constantes, que desafortunadament...

10  ¿Cómo puedo hacer un ejecutable portátil?  ( How can i make a portable executable ) 
¡Es una forma de compilar un archivo de origen C / C ++ para emitir un archivo .exe que se puede ejecutar en otros procesadores en diferentes computadoras? Es...

4  ¿Cuáles son algunas de las recomendaciones para portear el código C ++ a los macos? [cerrado]  ( What are some recommendations for porting c code to the macos ) 
Según lo que actualmente representa, esta pregunta no es un buen ajuste para nuestro Q & Amp; un formato. Esperamos que las...

2  Mezcla API openssl API y BSD Sockets API  ( Mixing openssl api and bsd sockets api ) 
Estoy escribiendo un cliente que debe lidiar con el protocolo HTTP ordinario y también HTTPS para conexiones seguras. Para las conexiones HTTP ordinarias, deb...

1  Python portátil (Mac -> Windows)  ( Portable python mac windows ) 
Ahora tengo un Macbook encantador, y estoy disfrutando de la codificación en movimiento. También estoy disfrutando de la codificación en Python. Sin embargo, ...

152  ¿Cómo debo imprimir tipos como OFF_T y STORSE_T?  ( How should i print types like off t and size t ) 
Estoy tratando de imprimir tipos como off_t y $(".some-button").live("click", function() { alert('yay!'); }); 0 . ¿Cuál es el marcador de posición correcto...

0  El problema de la portabilidad de las definiciones del formulario en las formas de orbeon  ( The portability issue of form definitions in orbeon forms ) 
Tienda Definiciones del formulario en un repositorio basado en sistemas de archivos. Cada definición del formulario en el repositorio tiene un file-id . En l...

1  ¿Puedo instalar Oracle en el XP portátil que está instalado en mi disco duro USB WD 160GB?  ( Can i install oracle on the portable xp which is installed on my wd 160gb usb ha ) 
por favor ayúdame. Quiero instalar un software de impresión de direcciones. En lugar de usar un disco duro interno, quería usar un disco duro USB para que m...

6  Cuestiones portadoras de punto flotante de 64 bits  ( 64 bit floating point porting issues ) 
Estoy transmitiendo mi aplicación de 32 bits a 64 bits. Actualmente, el código se compila bajo ambas arquitecturas, pero los resultados son diferentes. Por di...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos