in

¿Cuál es el efecto de extern «C» en C ++?

apple touch icon@2

Descompilar un g++ binario generado para ver qué está pasando

main.cpp

void f() {}
void g();

extern "C" {
    void ef() {}
    void eg();
}

/* Prevent g and eg from being optimized away. */
void h() { g(); eg(); }

Compile y desmonte la salida ELF generada:

g++ -c -std=c++11 -Wall -Wextra -pedantic -o main.o main.cpp
readelf -s main.o

La salida contiene:

     8: 0000000000000000     7 FUNC    GLOBAL DEFAULT    1 _Z1fv
     9: 0000000000000007     7 FUNC    GLOBAL DEFAULT    1 ef
    10: 000000000000000e    17 FUNC    GLOBAL DEFAULT    1 _Z1hv
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z1gv
    13: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND eg

Interpretación

Vemos eso:

  • ef y eg se almacenaron en símbolos con el mismo nombre que en el código

  • los otros símbolos estaban destrozados. Vamos a desmancharlos:

    $ c++filt _Z1fv
    f()
    $ c++filt _Z1hv
    h()
    $ c++filt _Z1gv
    g()
    

Conclusión: los dos tipos de símbolos siguientes fueron no destrozado:

  • definido
  • declarado pero indefinidoNdx = UND), que se proporcionará en el enlace o en tiempo de ejecución desde otro archivo de objeto

Entonces necesitarás extern "C" ambos al llamar:

  • C desde C ++: tell g++ esperar símbolos no mutilados producidos por gcc
  • C ++ desde C: tell g++ para generar símbolos no mutilados para gcc usar

Cosas que no funcionan en extern C

Resulta obvio que cualquier característica de C ++ que requiera alterar nombres no funcionará dentro extern C:

extern "C" {
    // Overloading.
    // error: declaration of C function ‘void f(int)’ conflicts with
    void f();
    void f(int i);

    // Templates.
    // error: template with C linkage
    template <class C> void f(C i) { }
}

Ejemplo de C mínimo ejecutable desde C ++

En aras de la integridad y para los novatos, consulte también: ¿Cómo usar archivos fuente C en un proyecto C ++?

Llamar a C desde C ++ es bastante fácil: cada función de C solo tiene un símbolo posible no mutilado, por lo que no se requiere trabajo adicional.

main.cpp

#include <cassert>

#include "c.h"

int main() {
    assert(f() == 1);
}

ch

#ifndef C_H
#define C_H

/* This ifdef allows the header to be used from both C and C++ 
 * because C does not know what this extern "C" thing is. */
#ifdef __cplusplus
extern "C" {
#endif
int f();
#ifdef __cplusplus
}
#endif

#endif

cc

#include "c.h"

int f(void) { return 1; }

Correr:

g++ -c -o main.o -std=c++98 main.cpp
gcc -c -o c.o -std=c89 c.c
g++ -o main.out main.o c.o
./main.out

Sin extern "C" el enlace falla con:

main.cpp:6: undefined reference to `f()'

porque g++ espera encontrar un destrozado f, cuales gcc no produjo.

Ejemplo en GitHub.

Ejemplo de C ++ ejecutable mínimo a partir de C

Llamar a C ++ desde C es un poco más difícil: tenemos que crear manualmente versiones no mutiladas de cada función que queremos exponer.

Aquí ilustramos cómo exponer las sobrecargas de funciones de C ++ a C.

C Principal

#include <assert.h>

#include "cpp.h"

int main(void) {
    assert(f_int(1) == 2);
    assert(f_float(1.0) == 3);
    return 0;
}

cpp.h

#ifndef CPP_H
#define CPP_H

#ifdef __cplusplus
// C cannot see these overloaded prototypes, or else it would get confused.
int f(int i);
int f(float i);
extern "C" {
#endif
int f_int(int i);
int f_float(float i);
#ifdef __cplusplus
}
#endif

#endif

cpp.cpp

#include "cpp.h"

int f(int i) {
    return i + 1;
}

int f(float i) {
    return i + 2;
}

int f_int(int i) {
    return f(i);
}

int f_float(float i) {
    return f(i);
}

Correr:

gcc -c -o main.o -std=c89 -Wextra main.c
g++ -c -o cpp.o -std=c++98 cpp.cpp
g++ -o main.out main.o cpp.o
./main.out

Sin extern "C" falla con:

main.c:6: undefined reference to `f_int'
main.c:7: undefined reference to `f_float'

porque g++ generó símbolos destrozados que gcc no puede encontrar.

Ejemplo en GitHub.

Dónde está el extern "c" cuando incluyo encabezados C de C ++?

Probado en Ubuntu 18.04.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

inner classes

Java – clases internas

gfg 200x200 min

Método stdev () en el módulo de estadísticas de Python