2010-05-09 17 views
6

Tengo un proyecto de C++ que utiliza un analizador de bisontes C. El analizador C utiliza una estructura de punteros de función para llamar a funciones que crean nodos AST adecuadas cuando las producciones son reducidas por el bisonte:C funciones de devolución de llamada definidas en un espacio de nombre sin nombre?

typedef void Node; 
struct Actions { 
    Node *(*newIntLit)(int val); 
    Node *(*newAsgnExpr)(Node *left, Node *right); 
    /* ... */ 
}; 

Ahora, en la parte C++ del proyecto, i llenar esos punteros

class AstNode { 
    /* ... */ 
}; 
class IntLit : public AstNode { 
    /* ... */ 
}; 

extern "C" { 
    Node *newIntLit(int val) { 
    return (Node*)new IntLit(val); 
    } 

    /* ... */ 
} 

Actions createActions() { 
    Actions a; 
    a.newIntLit = &newIntLit; 
    /* ... */ 
    return a; 
} 

Ahora, la única razón por la que los incluyo en extern "C" es porque quiero que tengan convenciones de llamadas en C. Pero de manera óptima, me gustaría que sus nombres sigan mutilados. Nunca se les llama por nombre desde el código C, por lo que el cambio de nombre no es un problema. Tenerlos destrozados evitará conflictos de nombres, ya que algunas acciones se llaman como error, y la función de devolución de llamada de C++ tiene nombres feos como los siguientes solo para evitar conflictos de nombres con otros módulos.

extern "C" { 
    void uglyNameError(char const *str) { 
    /* ... */ 
    } 

    /* ... */ 
} 

a.error = &uglyNameError; 

me preguntaban si podría ser posible con sólo dar el tipo de función C vinculación

extern "C" void fty(char const *str); 
namespace { 
    fty error; /* Declared! But i can i define it with that type!? */ 
} 

¿Alguna idea? Estoy buscando soluciones Standard-C++.

+0

¿No se puede compilar la salida de Bison como código C++, evitando así el problema por completo? –

+0

@Konrad, mi colega dijo que no es agradable trabajar con el modo binario C++, por lo que hacemos esa parte con C puro y la abstraemos, de modo que junto con el escáner constituye una biblioteca C pura. –

Respuesta

3

No entiendo el problema. La palabra clave extern no afecta la convención de llamadas, simplemente el nombre presentado al vinculador. Una función escrita en C++ que no es un método de instancia todavía es __cdecl, con o sin extern "C". Además, mientras mantenga createActions() en el mismo archivo de código fuente, estas funciones no necesitan vinculación externa. Puede declararlos estáticos o ponerlos en un espacio de nombre sin nombre para evitar colisiones.

+2

Ah, podría hacer entonces 'estático'. Buena idea, ¿por qué no pensé en eso? :) Solo pensé en los espacios de nombre no nombrados, pero eso no afectará su vinculación y no evitará conflictos para las funciones "externas" C ". ¡Pero 'estático' podría funcionar! Para las partes restantes de su respuesta: marcar la convención puede marcar la diferencia si la implementación lo desea. No quería depender de ninguna implementación en particular, así que los hice 'extern" C "'. –

Cuestiones relacionadas