tutorial programming example c++ function-pointers static-members linkage extern-c

c++ - programming - cuda tutorial



estático vs extern "C"/"C++" (5)

Generalmente hablando

Clases de almacenamiento:

las clases de almacenamiento se utilizan para indicar la duración y el alcance de una variable o identificador.

Duración:

La duración indica la vida útil de una variable.

Alcance:

El alcance indica la visibilidad de la variable.

Clase de almacenamiento estático:

La clase de almacenamiento estático se usa para declarar un identificador que es una variable local a una función o un archivo y que existe y retiene su valor después de que el control pase desde donde se declaró. Esta clase de almacenamiento tiene una duración que es permanente. Una variable declarada de esta clase conserva su valor de una llamada de la función a la siguiente. El alcance es local. Una variable es conocida solo por la función que está declarada dentro o si se declara globalmente en un archivo, es conocida o vista solo por las funciones dentro de ese archivo. Esta clase de almacenamiento garantiza que la declaración de la variable también inicializa la variable a cero o a todos los bits desactivados.

Clase de almacenamiento externo:

La clase de almacenamiento externo se usa para declarar una variable global que será conocida por las funciones en un archivo y será conocida por todas las funciones en un programa. Esta clase de almacenamiento tiene una duración que es permanente. Cualquier variable de esta clase conserva su valor hasta que sea cambiado por otra asignación. El alcance es global. Una variable puede ser conocida o vista por todas las funciones dentro de un programa.

¿Cuál es la diferencia entre una función miembro estática y una función de vinculación externa "C"? Por ejemplo, cuando uso "makecontext" en C ++, necesito pasar un puntero para funcionar. Google recomienda usar un enlace externo en "C", porque "makecontext" es C. Pero descubrí que el uso de estática también funciona. ¿Tengo suerte o ...

class X { public: static void proxy(int i) {} } makecontext(..., (void (*)(void)) X::proxy, ...);

vs

extern "C" void proxy(int i) {} makecontext(..., (void (*)(void)) proxy, ...);

EDITAR: ¿Puede mostrar un compilador o una arquitectura donde la versión miembro estática no funciona (y no es un error en el compilador)?


La mayor parte de lo que hace extern "C" depende en gran medida del compilador. Muchas plataformas cambian la convención de denominación y denominación basada en la declaración, pero nada de eso está especificado por el estándar. Realmente lo único que requiere el estándar es que el código en el bloque se puede llamar desde las funciones C. En cuanto a su pregunta específica, la norma dice:

Dos tipos de funciones con vínculos de idioma diferentes son tipos distintos, incluso si son idénticos.

Esto significa que el extern "C" void proxy(int i) {} y /*extern "C++"*/void proxy(int i) {} tienen diferentes tipos, y como resultado, los punteros a estas funciones también tendrían diferentes tipos. El compilador no falla su código por la misma razón por la que no fallaría un gran trabajo como:

int *foo = (int*)50; makecontext(..., (void (*)(void)) foo, ...);

Este código podría funcionar en alguna plataforma, pero eso no significa que funcionará en otra plataforma (incluso si el compilador era totalmente compatible con el estándar). Está aprovechando cómo funciona su plataforma en particular, lo que podría estar bien si no le preocupa escribir código portátil.

En cuanto a las funciones miembro estáticas, no se requiere que tengan un puntero para que el compilador tenga la libertad de tratarlas como una función no miembro. De nuevo, el comportamiento aquí es específico de la plataforma.


Sí, tienes suerte :) El "C" externo es un enlace de idioma para el lenguaje C que todos los compiladores de C ++ deben admitir, al lado de "C ++" externo, que es el valor predeterminado. Los compiladores pueden soportar otros enlaces de idiomas. GCC, por ejemplo, es compatible con "Java" externo, que permite interactuar con el código Java (aunque eso es bastante engorroso).

extern "C" le dice al compilador que su función se puede llamar por código C. Esto puede, pero no debe, incluir la convención de llamada apropiada y la manipulación del nombre del lenguaje C apropiado (a veces llamado "decoración"), entre otras cosas, dependiendo de la implementación. Si tiene una función miembro estática, la convención de llamada es la de su compilador de C ++. A menudo son los mismos que para el compilador de C de esa plataforma, así que dije que solo tienes suerte. Si tiene una API de C y pasa un puntero a una función, mejor coloque una en una función declarada con extern "C" como

extern "C" void foo() { ... }

Aunque el tipo de puntero de función no contiene la especificación de vinculación, se ve como

void(*)(void)

El enlace es una parte integral del tipo, simplemente no puede expresarlo directamente sin un typedef:

extern "C" typedef void(*extern_c_funptr_t)();

El compilador Comeau C ++, en modo estricto, emitirá un error, por ejemplo, si intenta asignar la dirección de la función externa "C" de arriba a (void(*)()) , porque es un puntero a una función con enlace C ++.


Tenga en cuenta que extern C es la forma recomendada de interoperabilidad C / C ++. Here está el maestro hablando de ello. Para agregar a la respuesta de eduffy: tenga en cuenta que las funciones y variables estáticas en el espacio de nombres global están en desuso. Utilice al menos un espacio de nombres anónimo.

Volver a extern C : si no usa extern C, tendrá que saber el nombre exacto y usarlo. Eso es mucho más de un dolor.


extern "C" desactiva el nombre del compilador de C ++ (que es necesario para la sobrecarga).

Si declara que una función en A.cpp es static , entonces B.cpp no ​​puede encontrarla (queda de C y tiene el mismo efecto de poner una función dentro de un espacio de nombres anónimo).