2009-09-15 12 views
5

Es posible escribir una clase o estructura C++ que sea totalmente compatible con C struct. De la compatibilidad quiero decir el tamaño del objeto y la ubicación de la memoria de las variables. Sé que es malo utilizar *(point*)&pnt o incluso (float*)&pnt (en un caso diferente donde las variables son flotantes), pero consideran que es realmente necesario para el rendimiento. No es lógico usar un operador de conversión de tipo regular millones de veces por segundo.C++ Compatibilidad de clase o estructura con C struct

Tome este ejemplo

Class Point { 
    long x,y; 
    Point(long x, long y) { 
     this->x=x; 
     this->y=y; 
    } 

    float Distance(Point &point) { 
     return ....; 
    } 
}; 

versión C es una estructura POD

struct point { 
    long x,y; 
}; 
+0

¿Con qué propósito quieres esta compatibilidad? ¿Desea pasar datos binarios de un programa C++ a un programa c, o desea pasar un objeto C++ a una función c? – Dima

+4

* "pero considere que es realmente necesario para el rendimiento. No es lógico usar un operador de conversión de tipo regular millones de veces por segundo." * Esto no tiene sentido para mí. – GManNickG

+0

@Dima: a la función C @GMan: método no malvado debe definir el operador de conversión de tipo punto de operador() { punto p; p.x = this-> x; p.y = this.y; return p; } Sin embargo, voy a utilizar estos puntos en dos casos int tipeado para pasar la función de ventanas para encontrar la posición del cursor. Float tipeado se envía a OpenGL como vértices (mientras se convierte en matriz flotante), primero se ejecuta uno por cada fotograma (350 veces/seg), otro es para 4 objetos x dibujados x 350. Se usarán dentro de un juego motor. –

Respuesta

8

Sí.

  • utilizar los mismos tipos en el mismo orden en ambos idiomas
  • Asegúrese de que la clase no tiene nada virtual en ella (lo que no se obtiene un puntero vtable pegado en la parte delantera)
  • Dependiendo de los compiladores utilizados, es posible que deba ajustar el empaque de la estructura (generalmente con pragmas) para garantizar la compatibilidad.

(editar)

  • Además, se debe tener cuidado para comprobar el sizeof() los tipos con sus compiladores. Por ejemplo, me he encontrado con un compilador que almacenó cortos como valores de 32 bits (cuando la mayoría usará 16). Un caso más común es que un int generalmente será de 32 bits en una arquitectura de 32 bits y de 64 bits en una arquitectura de 64 bits.
+0

En mi experiencia, los paquetes pragmas son una mala idea. Si ordena las variables miembro de modo que tengan una alineación natural, entonces los pragmas de paquete no son necesarios. Y si * no * les ordena que tengan una alineación natural e intentan usar pragmas para arreglarlo, puede encontrar dos problemas: 1) Los pragmas todavía no funcionarán 2) Forzarán al compilador a desalinear algo el procesador no quiere desalineados, como los números de coma flotante. En PowerPC, al menos, una flotación desalineada generará una interrupción manejada por software que puede * afectar significativamente * el rendimiento. – KeyserSoze

+0

Definir un objeto C++ con el mismo diseño que la estructura C funciona, pero no experess la intención tan claramente como tener la clase interet de la estructura (ver mi respuesta a continuación). –

+0

@keysersoze: Sí, la alineación natural es mejor. Sin embargo, algunos compiladores aún empaquetarán datos de manera diferente, que es donde es útil mencionar el empaque. De hecho, olvidé mencionar el cuidado con los tamaños de los miembros también. Editaré mi publicación para agregar ese punto. –

-2

Mientras que su clase no exhibir algunas características avanzadas de este tipo, como el crecimiento algo virtual, lo que debería ser más o menos la misma estructura.

Además, puede cambiar Class (que no es válido debido a las mayúsculas, de todos modos) a struct sin hacer ningún daño. Excepto que los miembros se volverán públicos (ahora son privados).

Pero ahora que pienso en su conversación acerca de la conversión de tipo ... No hay manera de que pueda convertir float en representando el mismo valor o viceversa mediante el tipo de puntero fundido. Espero que solo te interesen estos consejos para mover cosas.

+1

Cuando cambia struct a clase, el efecto _only_ es que el nivel de protección predeterminado (hasta el primer público explícito :, privado: o protegido :) se vuelve público, en lugar de privado. – bdonlan

+0

bdonlan, sí, lo mencioné. Pero no debes subestimar el lado emocional del trato ;-) –

+0

la versión flotante es un caso totalmente diferente (OpenGL) e int es para Windows (estructura de puntos). y el ejemplo de clase debería tener público: en la parte superior. Solo lo tiro como muestra. –

5

POD se aplica a C++. Puedes tener funciones de miembro. "A POD type in C++ is an aggregate class that contains only POD types as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type"

Debe diseñar sus estructuras de datos POD para que tengan una alineación natural, y luego se pueden pasar entre programas creados por diferentes compiladores en diferentes arquitecturas. La alineación natural es donde el desplazamiento de memoria de cualquier miembro es divisible por el tamaño de ese miembro. IE: un flotador está ubicado en una dirección que es divisible por 4, un doble está en una dirección divisible por 8. Si declara un char seguido de un flotante, la mayoría de las arquitecturas rellenarán 3 bytes, pero algunas podrían cubrir 1 byte. Si declara un flotador seguido de un char, todos los compiladores (debo agregar una fuente para este reclamo, lo siento) no se rellenarán.

+0

No hay garantía de que el compilador no inserte relleno extra, por lo que no puede estar * seguro * funcionará a menos que use un paquete pragma o similar. – jalf

+0

Nunca he visto un compilador que inserta relleno para estructuras que tienen una alineación natural. VC++ 6.0, 2003, 2005, 2008, Metrowerks para PPC, Metrowerks para HC12, gcc para ARM, gcc 2.98-3.x para PowerPC, gcc 3.x-4.x para x86, SDCC para 8051, Crossworks para MSP430. Apreciaría mucho escuchar un contraejemplo o una buena justificación de por qué esto es así. – KeyserSoze

+0

Si usa un paquete pragma en estructuras que aún no tienen una alineación natural, a menudo hay efectos secundarios dañinos. Si ha alineado floats incorrectamente en PowerPC, por ejemplo, se producirá una excepción de hardware. El manejador de hardware puede elegir reiniciar el procesador (común en las aplicaciones integradas) o manejar el problema en el software (que es SLOOOOW). En cualquier caso, usar un paquete pragma solo puede hacerte daño, definitivamente debes definir la estructura para tener una alineación natural y no usar un paquete para que funcione igual en todas las plataformas. – KeyserSoze

1

C y C++ son idiomas diferentes, pero siempre ha sido la intención de C++ que pueda tener una implementación que admita ambos idiomas de una manera binaria compatible.Debido a que son idiomas diferentes, siempre es un detalle de implementación del compilador si esto es realmente compatible. Normalmente, los proveedores que suministran un compilador C y C++ (o un compilador único con dos modos) admiten una compatibilidad total para pasar POD-structs (y punteros a POD-structs) entre el código C++ y el código C.

A menudo, simplemente tener un constructor definido por el usuario rompe la garantía aunque a veces se puede pasar un puntero a tal objeto a una función C esperando un puntero a struct con una estructura de datos idéntica y funcionará.

En resumen: verifique la documentación del compilador.

1

Usa la misma "estructura" tanto en C como en C++. Si desea agregar métodos en la implementación de C++, puede heredar la estructura y el tamaño debe ser el mismo siempre que no agregue miembros de datos o funciones virtuales.

Tenga en cuenta que si tiene una estructura vacía o miembros de datos que son estructuras vacías, son de diferentes tamaños en C y C++. En C, sizeof (empty-struct) == 0 aunque en C99, las estructuras vacías no deberían estar permitidas (pero pueden ser soportadas de todos modos como una "extensión de compilación"). En C++, sizeof (estructura-vacía)! = 0 (el valor típico es 1).

17

el más limpio era de hacer esto es a heredar de la estructura C:

struct point 
{ 
    long x, y; 
}; 

class Point : public struct point 
{ 
    public: 
    Point(long x, long y) 
     { this->x=x; this->y=y; } 

    float Distance(Point &point) 
     {    return ....;  } 
} 

El compilador de C++ garantiza el punto estructura de estilo C tiene el mismo diseño que con el compilador C. El punto de la clase C++ hereda este diseño para su porción de clase base (y dado que no agrega datos o miembros virtuales, tendrá el mismo diseño). Un puntero al punto de clase se convertirá en un puntero al punto de estructura sin un molde, ya que la conversión a un puntero de clase base siempre es compatible. Por lo tanto, puede usar objetos Point de clase y pasarles libremente punteros a las funciones C esperando un puntero para struct point.

Por supuesto, si ya hay un archivo de cabecera C que define el punto de estructura, puede simplemente incluirlo en lugar de repetir la definición.

+0

+1. Como dijo George Clooney: "¿Qué más?" ...^_^... – paercebal

+0

Esto es lo que me han encontrado. ¡Gracias! – Eonil

+0

Esto puede provocar problemas horribles, ya que los miembros de la estructura son públicos. Básicamente rompe completamente cualquier encapsulación. –

0

Además de otras respuestas, me aseguraré de no poner ningún especificador de acceso (público :, privado: etc.) en su clase/estructura C++. IIRC el compilador puede reordenar bloques de variables miembro de acuerdo con la visibilidad, de modo que private: int a; pubic: int b; pueda obtener una yb ronda intercambiada. Ver, por ejemplo, este enlace: http://www.embedded.com/design/218600150?printable=true
Admito estar desconcertado de por qué la definición de POD no incluye una prohibición en este sentido.