2011-09-10 15 views
10
typedef struct foo_s { 
    int a; 
} foo; 

typedef struct bar_s { 
    foo; 
    int b; 
} bar; 

Básicamente quiero hacer:¿Puedo 'extender' una estructura en C?

bar b; 
b.a; 

Yo sé que podría hacer b.foo_name.a si hubiera llamado la struct foo en bar, pero Id prefiero no hacerlo.

¿Alguna forma de hacerlo?

Esta pregunta ha recibido una variedad de respuestas diferentes, así que déjame explicarte la necesidad. La razón por la que quiero hacer esto es porque tengo una biblioteca que necesito adaptar a mi situación, lo que significa que no puedo modificar la declinación de la estructura original. Además, todo lo que necesito hacer es agregar 1 elemento al principio de la estructura (¿por qué al principio? Porque tengo una estructura 'objeto' que encabeza todas las estructuras en el proyecto). Simplemente podría insertar la estructura como mencionas pero es realmente molesto ya que todas las referencias deberán escribirse 'variable-> image.location' en 'imagen'. tipeó mil millones de tipos es realmente molesto.

+0

Algunos compiladores que ofrecen todo el comportamiento como una extensión Personalmente, creo que proporciona demasiado riesgo (anidar 'struct's a seis capas de profundidad y olvidar los nombres que has usado) así que solo nombro al primer miembro' _' - corto, consistente, fuera del camino, y no terriblemente inconveniente . (El nombre podría estar reservado por el estándar y/o el compilador, pero dudo que alguien lo use). –

+0

Si 'image' es molesto para escribir mucho, use' img'. Utilice find-and-replace para hacerlo por usted. No te preocupes: lo que sea que acabes teniendo que hacer, sobrevivirás. –

+0

@ chacham15 Amigo, evite etiquetar una pregunta C como C++. Estos dos idiomas son completamente diferentes. –

Respuesta

19

Evidentemente this feature has been added to C11, pero por desgracia no tengo acceso a un compilador C de la vendimia reciente (> = GCC 4.6.2).

typedef struct foo { 
    int a; 
} foo; 

typedef struct bar { 
    struct foo; 
    int b; 
} bar; 

int main() { 
    bar b; 
    b.a = 42; 
    b.b = 99; 
    return 0; 
} 
+1

Tenga en cuenta que esto funciona porque dentro de 'bar',' struct foo' se usa de forma anónima (es decir, sin un nombre de variable). –

7

No es posible en C como lo hizo. Pero puede imitar la herencia con una variable de miembro foo en bar.

typedef struct bar_s { 
    foo obj; 
    int b; 
} bar; 

bar b; 
b.obj.a = 10; 
+5

Eso se llama [composición] (http://en.wikipedia.org/wiki/Composition_over_inheritance) si no me equivoco. – michaelsnowden

1

Usted puede intentar usar la herencia:

struct foo_s 
{ 
    int a; 
}; 

struct bar_s: foo_a 
{ 
    int b; 
}; 

Obras en C++, no está seguro si funciona en C.

+1

mi mal, tienes razón, no sé por qué agregué la etiqueta C++, quise decir c. ¡Sry! – chacham15

+4

Estoy seguro de que no es C –

+0

La mejor respuesta, incluso si es C++. – lama12345

2

Si usted ción

typedef struct foo_s { 
    int a; 
    } foo; 

typedef struct bar_s { 
foo my_foo; 
int b; 
} bar; 

lo que puede hacer :

bar b; b.my_foo.a = 3; 

De lo contrario, no hay forma de hacerlo en C ya que el sizeof(bar_s) es perjudicial para el tiempo de compilación. No es una buena práctica, pero puede guardar un puntero void * ptr; dentro de bar_s, y otra enumeración que describe el tipo ptr, y enviar por tipo.

es decir:

typedef enum internalType{ 
    INTERNAL_TYPE_FOO = 0, 
}internalType_t; 

typedef struct bar_s { 
internalType_t ptrType; 
void* ptr; 
int b; 
} bar; 

y luego:

bar b; foo f; 
b.ptrType = INTERNAL_TYPE_FOO; 
b.ptr = &f; 

y en otro lugar en el código:

if (b.ptrType == INTERNAL_TYPE_FOO) { 
    foo* myFooPtr = (foo *)b.ptr; 
} 
+0

La pregunta no menciona el deseo de "tipos" de tiempo de ejecución como usted describe. –

+0

@Chris Lutz Tal vez por la borda, pero aborda la pregunta ... –

+0

@Chris, puede que tengas razón, pero el "bar.a" me pareció un código python (donde las clases se pueden extender en tiempo de ejecución) . Así que eso es lo primero que me vino a la mente ... –

9

Usted puede, usando punteros, porque un puntero a una estructura objeto está garantizado para apuntar a su primer miembro. Ver p. this article.

#include <stdlib.h> 
#include <stdio.h> 

typedef struct foo_s { 
    int a; 
} foo; 

typedef struct bar_s { 
    foo super; 
    int b; 
} bar; 

int fooGetA(foo *x) { 
    return x->a; 
} 

void fooSetA(foo *x, int a) { 
    x->a = a; 
} 

int main() { 
    bar* derived = (bar*) calloc(1, sizeof(bar)); 
    fooSetA((foo*) derived, 5); 
    derived->b = 3; 
    printf("result: %d\n", fooGetA((foo*) derived)); 
    return 0; 
} 
+1

Es incluso mejor cuando toman punteros 'void *' y evitan la conversión del lado de la persona que llama. (Los valores de "mejor" de algunas personas pueden ser diferentes a los míos.) –

+1

Sí, ciertamente es más conveniente para la persona que llama. Quería demostrar que el autor de las funciones de foo no tiene que saber que la estructura "real" es algo más que foo. –

+1

Bueno, ambos enfoques son correctos e incorrectos al mismo tiempo. Tener que encasillar obliga al código del cliente a ser de baja calidad. Esto se puede resolver usando 'void *', sin embargo, eso elimina la seguridad del tipo que es aún peor. Aún así, estas son una buena respuesta y algunos buenos argumentos, especialmente el último comentario de Jouni cuando se trata de abstracciones (el punto de la herencia), sin embargo, los factores anteriores deben tenerse en cuenta. Aquí está la solución C11: ** http: //modelingwithdata.org/arch/00000113.htm**; Me pregunto si hubo una solución para otras versiones de C – Powerslave

0

Se puede hacer fácilmente a través de preprocesador:

Crear un archivo llamado base_foo.h:

int foo; 

Después, simplemente lo incluyen:

typedef struct foo_s { 
    #include "base_foo.h" 
} foo; 

typedef struct bar_s { 
    #include "base_foo.h" 
    int b; 
} bar;