Pregunta

¿Cuál es la diferencia entre una función miembro estática y una función de enlace extern "C"? Por ejemplo, cuando se utiliza "makecontext" en C ++, necesito pasar un puntero a funcionar. Google recomienda el uso de extern vinculación "C" para ello, porque "makecontext" es C. Sin embargo, he encontrado que el uso de obras estáticas también. ¿Soy sólo 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, ...);

EDIT:? ¿Se puede mostrar un compilador o la arquitectura, donde la versión miembro estático no funciona (y no es un error en el compilador)

¿Fue útil?

Solución

Sí, usted es sólo suerte :) El extern "C" es una unión idioma para el lenguaje C que cada compilador de C ++ tiene que apoyar, junto extern "C ++", que es el valor predeterminado. Los compiladores pueden apoya otros vínculos de idioma. GCC, por ejemplo, apoya extern "Java", que permite interactuar con el código de Java (aunque eso es bastante engorroso).

extern "C" indica al compilador que su función es exigible por el código C. Que puede, pero no debe, incluir la convención de llamada correspondiente y el nombre del idioma apropiado mangling C (a veces llamado "decoración"), entre otras cosas, dependiendo de la aplicación. Si usted tiene un método estático, la convención de llamada para ello es el de su compilador de C ++. A menudo son las mismas que para el compilador de C de esa plataforma - Así que le dije usted es sólo suerte. Si usted tiene una API C y se pasa un puntero de función, siempre mejor poner uno a una función declarada con extern "C" como

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

A pesar de que el tipo de puntero de función no contiene la especificación de vinculación, sino más bien se parece a

void(*)(void)

La vinculación es una parte integral del tipo - que no se puede expresar directamente sin un typedef:

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

El compilador Comeau C ++, en modo estricto, se emite un error, por ejemplo, si se intenta asignar la dirección de la función extern "C" de arriba a un (void(*)()), beause este es un puntero a una función con C vinculación ++.

Otros consejos

Tenga en cuenta, que es la recomendada extern C modo de / interoperabilidad C C ++. Aquí es el maestro de hablar de ello. Para añadir a la respuesta de eduffy: cuenta que las funciones estáticas y variables en el espacio de nombres global están en desuso. Utilizar un espacio de nombres en el anonimato por lo menos.

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

extern "C" desactiva el nombre del compilador C ++ mangling (que se requiere para la sobrecarga).

Si se declara una función en a.cpp ser static, entonces no puede ser encontrado por B.cpp (que es de sobra de C, y tiene el mismo efecto de poner una función dentro de un espacio de nombres en el anonimato).

La mayoría de lo extern "C" hace es en gran medida dependiente del compilador. Muchas plataformas cambian el nombre y para dar convención de llamada con sede fuera de la declaración, pero nada de eso se ha especificado por la norma. Realmente lo único que la norma requiere es que el código en el bloque es exigible a partir de funciones C. En cuanto a su pregunta específica, la norma dice:

  

dos tipos de eventos de diferentes   vínculos de idioma son tipos distintos   incluso si son de otro modo idénticas.

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

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

Este código podría trabajar en alguna plataforma, pero eso no significa que vaya a trabajar en otra plataforma (incluso si el compilador era totalmente compatible con estándar). Usted está tomando ventaja de cómo funciona su plataforma en particular, lo que podría ser aceptable si no está preocupado acerca de cómo escribir código portable.

En cuanto a los métodos estáticos, que no están obligados a tener un puntero this lo que el compilador es libre para tratarlos como una función no miembro. Una vez más, el comportamiento aquí es específico de la plataforma.

En términos generales

clases almacenamiento:

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

Duración:

Duración indica el tiempo de vida de una variable.

Alcance:

Ámbito indica la visibilidad de la variable.

clase de almacenamiento estático:

La clase de almacenamiento estático se utiliza para declarar un identificador que es una variable local, ya sea a una función o un archivo y que existe y conserva su valor después el control pasa desde donde fue declarado. 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 sólo por la función se declara dentro o si se declara globalmente en un archivo, se sabe o se ve sólo 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 todos los bits o apagado.

clase de almacenamiento Extern:

La clase de almacenamiento externo se utiliza para declarar una variable global que se dará a conocer a las funciones en un archivo y capaz de ser conocido a 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 se cambie por otra asignación. El alcance es global. Una variable puede ser conocido o visto por todas las funciones dentro de un programa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top