Interpretación de macro feo (sólo 1 línea)

#define STRING(s) (((String*)s)-1) 

¿Qué en el mundo es (((String*)s)-1) ?

 typedef struct String { int length; int capacity; unsigned check; char ptr[0]; } String; 

Estás lanzando s a un String * . Entonces estás restando uno de eso (haciéndolo apuntar a lo que sea anterior).

Algo más específico necesitaría conocer la definición de String , pero (ESPECULACIÓN SALVAJE) supongo que la aplicación utiliza cadenas de estilo VB / C duales (terminadas en nulo, precedidas por la longitud), y esta función lo cambia de una forma adecuada para C funciona (puntero al primer carácter) en uno utilizable para el otro tipo (puntero a la longitud).

Mecánicamente, la macro funciona como otros ya lo han descrito. Semánticamente, sin embargo, puedes pensar en esto como una forma de lanzar desde char * s a String * s.

La estructura de String es el encabezado de una cadena contada, es decir, una en la que se conoce la longitud total sin tener que buscar un byte NUL. Esta versión en particular también mantiene el total asignado. Deberías crear uno de la siguiente manera:

 struct String *str = malloc(sizeof(*s) + maxlen); str->length = 0; str->capacity = maxlen; str->checked = /* ??? */; 

Debería haber algunas funciones variadas en algún lugar para manipular estas cadenas contadas.

La macro en sí es un truco para pasar de un char * simple char * , se supone que apunta al primer carácter de la String como se asignó anteriormente, de nuevo a una String * . Se usaría algo como esto:

 /* allocate str as above */ char *s = str->p; 

Ahora, a través de una cadena de llamadas o devoluciones de funciones, de alguna manera pierde el rastro de la estructura de Cadena que contiene s , y necesita encontrarla nuevamente. Usted escribe:

 String *str2 = STRING(s); 

Esta no es una forma particularmente buena de implementar una cadena contada en C, pero demuestra una técnica que uno ve de vez en cuando.

Otros han respondido a tu pregunta. La técnica de declarar ptr inside struct String con tamaño cero se llama ” la estructura hack ” y no fue portátil hasta C99 (aunque fue ampliamente utilizada incluso antes de C99, y parece funcionar en todas partes). La idea es que ptr utiliza 0 bytes, por lo que si tiene un puntero a ptr y desea uno a la estructura original, usaría la macro STRING . Está restando el tamaño de la struct de la dirección del miembro ptr y, por lo tanto, obtiene la dirección de inicio de la struct .

Una mejor manera de obtener la dirección de inicio de una struct dada un puntero a cualquiera de sus miembros es usar la macro offsetof() definida en stddef.h . offsetof(struct type, member) , como su nombre lo indica, proporciona el offset de member en struct type :

 #define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr)))) 

Entonces puedes hacer:

 #include  #include  #include  typedef struct String { int length; int capacity; unsigned check; char ptr[0]; } String; #define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr)))) int main(void) { String *s = malloc(sizeof *s + 100); String *t; char *mystring = s->ptr; t = STRING(mystring); assert(t == s); return EXIT_SUCCESS; } 

offsetof() se define en stddef.h .

Tenga en cuenta que en C99, “struct hack” declararía ptr dentro de la struct como:

 char ptr[]; 

Es decir, sin un tamaño.

  • (String *) = escriba cast to pointer to String object,
  • s = la cuerda,
  • -1 = punto a la longitud de un objeto String antes en el bloque de memoria

No sé por qué la macro se hace de esta manera. Posiblemente la definición de Cadena lo requiera, pero eso es solo una suposición descabellada.