Estructuras O opacas: ¿cómo deberían declararse?
coding-style typedef (2)
Mi voto es para la tercera opción que mouviciel publicó y eliminó:
He visto una tercera forma:
// foo.h struct foo; void doStuff(struct foo *f); // foo.c struct foo { int x; int y; };
Si realmente no puede soportar escribir la palabra clave struct
, typedef struct foo foo;
(nota: deshacerse del subrayado inútil y problemático) es aceptable. Pero haga lo que haga, nunca use typedef
para definir nombres para tipos de punteros. Oculta la información extremadamente importante de que las variables de este tipo hacen referencia a un objeto que podría modificarse cada vez que las pasas a funciones, y hace que lidiar con versiones del puntero con calificaciones diferentes (por ejemplo, const
-qualified) sea un gran dolor .
He visto los dos estilos siguientes de declarar tipos opacos en las API de C. ¿Hay alguna ventaja clara al usar un estilo sobre el otro?
Opción 1
// foo.h
typedef struct foo * fooRef;
void doStuff(fooRef f);
// foo.c
struct foo {
int x;
int y;
};
opcion 2
// foo.h
typedef struct _foo foo;
void doStuff(foo *f);
// foo.c
struct _foo {
int x;
int y;
};
bar(const fooRef)
declara una dirección inmutable como argumento. bar(const foo *)
declara una dirección de un foo inmutable como argumento.
Por esta razón, tiendo a preferir la opción 2. Es decir, el tipo de interfaz presentado es uno donde la cv-ness se puede especificar en cada nivel de indirección. Por supuesto, uno puede eludir la opción 1 escritor de la biblioteca y simplemente usar foo
, abriéndose a todo tipo de horror cuando el escritor de la biblioteca cambia la implementación. (Es decir, la opción 1 de escritor de la biblioteca solo percibe que fooRef
es parte de la interfaz invariante y que foo
puede ir, ir, alterarse, lo que sea. La opción 2 el escritor de la biblioteca percibe que foo
es parte de la interfaz invariante).
Estoy más sorprendido de que nadie sugiera construcciones typedef / struct combinadas.
typedef struct { ... } foo;