Ответ 1
Никто не должен этого делать. Если вы перестраиваете элементы структуры, у вас проблемы.
Я только что нашел еще одну базу кода на работе, где разработчики последовательно используют адрес первого элемента structs при копировании/сравнении/настройке, а не в самой структуре. Вот простой пример.
Сначала введите тип структуры:
typedef struct {
int a;
int b;
} foo_t;
Тогда существует функция, которая создает копию такой структуры:
void bar(foo_t *inp)
{
foo_t l;
...
memcpy(&l.a, &inp->a, sizeof(foo_t));
...
}
Я бы сам не написал вызов memcpy
таким образом, и я начал с подозрения, что оригинальные разработчики просто не совсем поняли указатели и структуры на C. Однако теперь я видел это в двух несвязанные базы кода, без общих разработчиков, поэтому я начинаю сомневаться в себе.
Почему нужно использовать этот стиль?
Никто не должен этого делать. Если вы перестраиваете элементы структуры, у вас проблемы.
Вместо этого:
memcpy(&l.a, &inp->a, sizeof(foo_t));
вы можете сделать это:
memcpy(&l, inp, sizeof(foo_t));
В то время как это может быть опасно и вводить в заблуждение, оба утверждения фактически делают то же самое здесь, что C гарантирует, что перед первым элементом структуры не будет прокладка.
Но лучше всего просто скопировать объекты структуры с помощью простого оператора присваивания:
l = *inp;
Почему нужно использовать этот стиль?
Мое предположение: невежество или плохая дисциплина.
Не было бы. Если вы когда-либо перемещали a
в структуру или вы вставляли ее элементы (ы), вы вводили ошибку памяти.
Этот код небезопасен, потому что переупорядочение элементов структуры может привести к тому, что memcpy
получит доступ за пределы структуры, если член a
уже не первый член.
Однако, возможно, что члены намеренно упорядочены внутри структуры, а программист только хочет скопировать подмножество из них, начиная с члена a
и запуская до конца структуры. В этом случае код можно сделать безопасным со следующим изменением:
memcpy(&l.a, &inp->a, sizeof(foo_t) - offsetof(foo_t, a));
Теперь члены структуры могут быть перегруппированы в любой порядок, и этот memcpy
никогда не выйдет за рамки.
Это очень плохая привычка. Например, структура может иметь, например, другой член. Это безумно неосторожная привычка, и я с удивлением узнаю, что кто-то это сделает.
Другие уже отметили это; тот, который меня беспокоит, таков:struct Foo rgFoo [3];
struct Foo *pfoo = &rgFoo [0];
вместо
struct Foo *pfoo = rgfoo;
Зачем выделять массив по индексу, а затем снова принимать адрес? Это уже адрес, единственное отличие в том, что pfoo технически
struct Foo *const,
not
struct Foo *.
Но я все время видел первый.
На самом деле для этого есть один законный прецедент: построение иерархии классов.
При обработке структур как экземпляров класса первый член (т.е. смещение 0) обычно будет экземпляром супертипа... если существует супертип. Это позволяет простому движению перемещаться между использованием подтипа и супертипа. Очень полезно.
В отношении Darren Stone обратите внимание на намерение, это ожидается при выполнении OO на языке C.
В любом другом случае я бы предложил избежать этого шаблона и получить доступ к элементу напрямую, по причинам, уже указанным.