lenguaje - Cómo inicializar una estructura con un miembro de matriz flexible
typedef struct en c (3)
Tengo la siguiente estructura
typedef struct _person {
int age;
char sex;
char name[];
}person;
He hecho una búsqueda básica en Internet (pero no exitosa) sobre cómo crear una instancia e inicializar una estructura con un miembro de matriz flexible sin usar malloc()
.
Por ejemplo: para estructuras normales como
struct a {
int age;
int sex;
};
Podemos crear una instancia de struct a
e inicializarla como
struct a p1 = {10, ''m''};
Pero para estructuras con una matriz flexible (como _person
como se mencionó anteriormente), ¿cómo podemos crear una instancia e inicializarla como lo hacemos para las structures
normales?
¿Es incluso posible? Si es así, ¿cómo pasamos el tamaño de la matriz durante la inicialización y el valor real a inicializar?
(o)
¿Es cierto que la única forma de crear una estructura con matriz flexible es usar malloc()
como se menciona en la especificación C99 - 6.7.2.1 Structure and union specifiers - point #17
?
Hay algunos trucos que puedes usar. Depende de su aplicación particular.
Si desea inicializar una sola variable, puede definir una estructura del tamaño correcto:
struct {
int age;
char sex;
char name[sizeof("THE_NAME")];
} your_variable = { 55, ''M'', "THE_NAME" };
El problema es que tienes que usar el lanzamiento de punteros para interpretar la variable como "persona" (por ejemplo, "* (persona *) (y tu_variable)". Pero puedes usar una unión contenedora para evitar esto:
union {
struct { ..., char name[sizeof("THE_NAME")]; } x;
person p;
} your_var = { 55, ''M'', "THE_NAME" };
entonces, your_var.p es de tipo "persona". También puede usar una macro para definir su inicializador, por lo que puede escribir la cadena solo una vez:
#define INIVAR(x_, age_, sex_ ,s_) /
union {/
struct { ..., char name[sizeof(s_)]; } x;/
person p;/
} x_ = { (age_), (sex_), (s_) }
INIVAR(your_var, 55, ''M'', "THE NAME");
Otro problema es que este truco no es adecuado para crear una matriz de "persona". El problema con las matrices es que todos los elementos deben tener el mismo tamaño. En este caso, es más seguro utilizar un const char *
lugar de un char[]
. O utilizar la asignación dinámica;)
No, los arreglos flexibles siempre deben asignarse manualmente. Pero puede usar calloc
para inicializar la parte flexible y un literal compuesto para inicializar la parte fija. Lo envolvería en una función de asignación en inline
como esta:
typedef struct person {
unsigned age;
char sex;
size_t size;
char name[];
} person;
inline
person* alloc_person(int a, char s, size_t n) {
person * ret = calloc(sizeof(person) + n, 1);
if (ret) memcpy(ret,
&(person const){ .age = a, .sex = s, .size = n},
sizeof(person));
return ret;
}
Observe que esto deja la verificación si la asignación fue exitosa para la persona que llama.
Si no necesita un campo de size
como lo incluí aquí, una macro sería suficiente. Solo que no sería posible verificar la devolución de calloc
antes de hacer el memcpy
. Bajo todos los sistemas que programé hasta ahora esto abortará relativamente bien. En general, creo que el retorno de malloc
es de poca importancia , pero las opiniones varían en gran medida sobre ese tema.
Esto quizás podría (en ese caso especial) dar más oportunidades al optimizador para integrar el código en el entorno:
#define ALLOC_PERSON(A, S, N) /
((person*)memcpy(calloc(sizeof(person) + (N), 1), /
&(person const){ .age = (A), .sex = (S) }, /
sizeof(person)))
Edición: el caso de que esto podría ser mejor que la función es cuando A
y S
son constantes de tiempo de compilación. En ese caso, el literal compuesto, ya que está const
, podría asignarse de forma estática y su inicialización podría realizarse en tiempo de compilación. Además, si varias asignaciones con los mismos valores aparecerían en el código, al compilador se le permitiría realizar solo una copia única de ese literal compuesto.
Un tipo de estructura con un miembro de matriz flexible puede tratarse como si se hubiera omitido el miembro de matriz flexible, por lo que puede inicializar la estructura de esta manera.
person p = { 10, ''x'' };
Sin embargo, no hay miembros de la matriz flexible asignados y cualquier intento de acceder a un miembro de la matriz flexible o formar un puntero a uno más allá de su extremo no es válido. La única forma de crear una instancia de una estructura con un miembro de matriz flexible que realmente tenga elementos en esta matriz es asignarle dinámicamente memoria, por ejemplo con malloc
.