Уродливая Макро Интерпретация (всего 1 строка)

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

что в мире есть (((String*)s)-1) ?

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

Вы бросаете s в String * . Затем вы вычитаете один из них (чтобы он указывал на предыдущее).

Что-нибудь более конкретное должно было бы знать определение String – но (ДИКИЙ СПЕКУЛЯЦИИ) Я бы предположил, что приложение использует две строки в стиле VB / C (с нулевым завершением, которому предшествует длина), и эта функция меняет его из формы, подходящей для C (указатель на первый символ) в один используемый для другого типа (указатель на длину).

Механически макрос работает, как другие уже описали его. Семантически, однако, вы можете рассматривать это как форму кастинга от char * s до String * s.

String структура – это заголовок подсчитанной строки, т. String Тот, где вы знаете общую длину без необходимости сканирования для NUL-байта. Эта конкретная версия также удерживает общее выделение. Вы должны создать его следующим образом:

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

Там должны быть какие-то разнообразные функции, чтобы манипулировать этими подсчитанными строками.

Сам макрос является взломом, чтобы перейти от простого char * , предположив, что он указывает на первый символ String как указано выше, назад к String * . Он будет использоваться примерно так:

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

Теперь, через цепочку вызовов функций или возвратов, вы как-то теряете следы строковой структуры, содержащей s , и вам нужно найти ее снова. Ты пишешь:

 String *str2 = STRING(s); 

Это не очень хороший способ реализовать подсчитанную строку в C, но она демонстрирует технику, которую время от времени видит.

Другие ответили на ваш вопрос. Техника объявления ptr внутри struct String с нулевым размером называется « struct hack » и не переносима до C99 (хотя она широко использовалась даже до C99 и, похоже, работает повсюду). Идея состоит в том, что ptr использует 0 байт, поэтому, если у вас есть указатель на ptr и вы хотите создать исходную структуру, вы должны использовать макрос STRING . Вы вычитаете размер struct из адреса члена ptr и, таким образом, получаете начальный адрес struct .

Лучшим способом получить начальный адрес struct заданной указателем на любой из ее членов, является использование макроса offsetof() определенного в stddef.h . offsetof(struct type, member) , как следует из названия, дает смещение member в виде struct type :

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

Тогда вы можете сделать:

 #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() определяется в stddef.h .

Обратите внимание, что в C99 «struct hack» объявит ptr внутри struct следующим образом:

 char ptr[]; 

т.е. без размера.

  • (String *) = тип cast для указателя на объект String,
  • s = строка,
  • -1 = указывает на длину одного объекта String в блоке памяти

Не знаю, почему макрос сделан таким образом. Возможно, определение String требует этого, но это просто дикая догадка.