c struct offsetof

¿Por qué es necesario compensar macro?



struct offsetof (3)

Soy nuevo en el lenguaje C y acabo de aprender sobre estructuras y punteros.

Mi pregunta está relacionada con el offsetof macro que vi recientemente. Sé cómo funciona y la lógica detrás de eso.

En el archivo <stddef.h> la definición es la siguiente:

#define offsetof(type,member) ((unsigned long) &(((type*)0)->member))

Mi pregunta es, si tengo una estructura como se muestra a continuación:

struct test { int field1: int field2: }; struct test var;

¿Por qué no puedo obtener directamente la dirección de field2 como:

char * p = (char *)&var; char *addressofField2 = p + sizeof(int);

En lugar de escribir algo como esto

field2Offset = offsetof (struct test, field2);

y luego agregar valor de compensación a la dirección de inicio de var?

Hay alguna diferencia? ¿Está usando offsetof más eficiente?


A diferencia de las matrices, el diseño de memoria de struct no siempre es contiguo. El compilador puede agregar bytes adicionales para alinear la memoria. Esto se llama padding .

Debido al relleno, es difícil encontrar la ubicación del miembro manualmente. Esta es también la razón por la que siempre usamos sizeof para encontrar el tamaño de la estructura.

Offsetof, macro le permite conocer la distancia, desplazamiento, de un miembro de struct desde la posición de estratagema de la estructura.

Un uso inteligente si offsetof se ve en el container_of macro del kernel de Linux. Este macro le permite conocer la posición inicial del nodo dada la dirección del miembro en una lista genérica doblemente enlazada inclusiva


Como ya se mencionó en las otras respuestas, el relleno es una de las razones. No repetiré lo que ya se dijo al respecto.

Otra buena razón para usar el offsetof macro y no calcular manualmente las compensaciones es que solo tiene que escribirlo una vez. Imagine lo que sucede si necesita cambiar el tipo de field1 o inserte o elimine uno o más campos en frente del field2 . Usando su cálculo hecho a mano, tiene que encontrar y cambiar todas sus ocurrencias. Perder uno de ellos producirá errores misteriosos que son difíciles de encontrar.

El código escrito usando offsetof no necesita ninguna actualización en esta situación. El compilador se ocupa de todo en la próxima compilación.

Aún más, el código que usa offsetof es más claro. La macro es estándar, su funcionalidad está documentada . Un compañero programador que lee el código lo comprende de inmediato. No es tan fácil de entender lo que intenta el código artesanal.


El compilador de C a menudo agregará bits o bytes adicionales entre los miembros de una struct para mejorar la eficiencia y mantener los enteros alineados con las palabras (lo que en algunas arquitecturas es necesario para evitar errores de bus y en algunas arquitecturas es necesario para evitar problemas de eficiencia). Por ejemplo, en muchos compiladores, si tiene esta struct :

struct ImLikelyPadded { int x; char y; int z; };

es posible que encuentre que sizeof(struct ImLikelyPadded) es 12, no 9, porque el compilador insertará tres bytes de relleno adicionales entre el final de la char y un byte y la palabra de tamaño int z . Esta es la razón por la que offsetof es tan útil: te permite determinar dónde están realmente las cosas, incluso teniendo en cuenta los bytes de relleno y es muy portátil.