Estructuras C opacas: ¿cómo deben declararse?


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;
};

Opción 2

// foo.h
typedef struct _foo foo;
void doStuff(foo *f);

// foo.c
struct _foo {
    int x;
    int y;
};
Author: splicer, 2010-10-19

2 answers

Mi voto es por la tercera opción que mouviciel publicó y luego eliminó:

He visto una tercera vía:

// foo.h
struct foo;
void doStuff(struct foo *f);

// foo.c
struct foo {
    int x;
    int y;
};

Si realmente no puedes soportar escribir la palabra clave struct, typedef struct foo foo; (nota: deshazte del subrayado inútil y problemático) es aceptable. Pero hagas lo que hagas, nunca use typedef para definir nombres para tipos de puntero. 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 pasarlos a las funciones, y hace que lidiar con versiones del puntero calificadas de manera diferente (por ejemplo, const calificadas) sea un dolor mayor.

 62
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-19 04:23:05

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 cv-ness se puede especificar en cada nivel de indirección. Por supuesto, uno puede eludir la opción 1 library writer y simplemente usar foo, abriéndose a todo tipo de horror cuando el library writer cambia la implementación. (Es decir, el escritor de la biblioteca de la opción 1 solamente percibe que fooRef es parte de la interfaz invariante y que foo puede venir, ir, alterarse, lo que sea. El escritor de la biblioteca de opción 2 percibe que foo es parte de la interfaz invariante.)

Me sorprende más que nadie haya sugerido construcciones combinadas typedef/struct.
typedef struct { ... } foo;

 1
Author: Eric Towers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-06 18:30:55