Назначение структуры C использует memcpy

У меня есть этот StructType st = StructTypeSecondInstance->st;, и он генерирует segfault. Странная часть, когда трассировка стека показывает мне:

0x1067d2cc: memcpy + 0x10 (0, 10000, 1, 1097a69c, 11db0720, bfe821c0) + 310
0x103cfddc: some_function + 0x60 (0, bfe823d8, bfe82418, 10b09b10, 0, 0) +

Итак, присваивание структуры использует memcpy?


person coredump    schedule 13.09.2012    source источник


Ответы (4)


Нельзя сказать. Небольшие структуры могут даже храниться в регистрах. Использование memcpy является деталью реализации (это даже не определяется реализацией или не указано — это просто то, что выбирает автор компилятора и не требует документирования).

С точки зрения стандарта C все, что имеет значение, это то, что после присваивания элементы структуры целевой структуры сравниваются с соответствующими элементами исходной структуры.

Я ожидаю, что разработчики компиляторов найдут компромисс между скоростью и простотой, вероятно, в зависимости от размера структуры, чем больше, тем больше вероятность использования memcpy. Некоторые реализации memcpy очень сложны и используют разные алгоритмы в зависимости от того, равна ли длина некоторой степени двойки или нет, или от выравнивания указателей src и dst. Зачем изобретать велосипед или взрывать код встроенной версией memcpy?

person Jens    schedule 13.09.2012
comment
› это просто то, что выбирает автор компилятора и не нужно документировать. Я считаю, что хороший ABI определяет эту проблему. Но не уверен) - person ThomasMore; 13.09.2012
comment
это немного странно для меня, потому что, похоже, он опирается на стандартную библиотеку C, в то время как у вас может не быть ее, например, при кросс-компиляции для встроенной системы. это было скомпилировано с оптимизацией? - person Gir; 13.09.2012
comment
@Gir: если вы выполняете кросс-компиляцию для встроенной системы без стандартной библиотеки, вы сообщаете об этом компилятору с помощью флагов, и тогда он не выдает эти вызовы lib. - person Stephen Canon; 13.09.2012
comment
@ThomasMore Просто нет ABI для того, как скопировать структуру, адресованную авторам компилятора. - person Jens; 13.09.2012
comment
@ThomasMore: я прочитал много документов ABI (и помог написать один); Я никогда не видел, чтобы кто-то определял, как выполняется назначение языка C. - person Stephen Canon; 13.09.2012
comment
@Jens да, кажется, я запутался, где передать структуру и как скопировать структуру - person ThomasMore; 13.09.2012

Может, да.

В этом нет ничего удивительного: присваивание структуры должно как можно быстрее скопировать группу байтов из одного места в другое, что, как оказалось, является именно тем, в чем memcpy() должен хорошо разбираться. Генерация вызова кажется легкой задачей, если вы пишете компиляторы.

Обратите внимание, что это означает, что назначение структур с большим количеством отступов может быть менее эффективным, чем оптимальное, поскольку memcpy() не может пропустить отступы.

person unwind    schedule 13.09.2012
comment
Итак, что за оператор присваивания — это просто синтаксический сахар для memcpy? - person coredump; 13.09.2012
comment
@coredump вы можете копировать 32- и 64-битные объекты, используя инструкции asm. Так что ответ скорее нет, чем да - person ThomasMore; 13.09.2012
comment
@coredump: нет, оператор присваивания — это оператор присваивания. Стандарт ничего не говорит о том, как компилятор должен на самом деле выполнять присваивание, поэтому он может выбирать то, что считает самым быстрым. Он мог копировать байт за байтом, он мог копировать каждое поле с естественной копией для его типа, он мог использовать встроенную реализацию memcpy, он мог вызывать memcpy,... - person Stephen Canon; 13.09.2012

Стандарт вообще ничего не говорит о том, как присваивание (или любой другой оператор) на самом деле реализуется компилятором. Ничто не мешает компилятору (скажем) генерировать вызов функции для каждой операции в вашем исходном файле.

Компилятор имеет лицензию на реализацию присваивания так, как считает нужным. В большинстве случаев, с большинством компиляторов на большинстве платформ, это означает, что если структура достаточно мала, компилятор будет генерировать встроенную последовательность инструкций перемещения; если структура большая, обычно вызывается memcpy.

Однако было бы совершенно правильно, если бы компилятор циклически генерировал случайные битовые поля и останавливался, когда одно из них совпадает с источником присваивания (назовем этот алгоритм bogocopy).

Компиляторы, которые поддерживают работу без хостинга, обычно дают вам переключатель для отключения таких вызовов libc, если вы ориентируетесь на платформу без доступной (или полной) libc.

person Stephen Canon    schedule 13.09.2012
comment
В качестве крайне незначительного примечания: *p = *p; иногда допустимо, а memcpy(p, p, sizeof(t)); никогда (в отличие от 6.5.16.1:3 и 7.21.2.1 C99). Компилятор может поставляться с memcpy(), который работает с полностью перекрывающимися аргументами, но когда он заменяет назначение структуры на memcpy(), он не просто предполагает наличие функции memcpy(), он предполагает, что вы используете ее< /b> функция, которая обрабатывает memcpy(p, p, sizeof(t));. Случайная memcpy() функция не обязана. - person Pascal Cuoq; 19.09.2012

Это зависит от компилятора и платформы. Для назначения больших объектов можно использовать memcpy. Но это не должно быть причиной segfault.

person ThomasMore    schedule 13.09.2012
comment
Да, конечно, нет, но я был удивлен, увидев вызов memcpy. - person coredump; 13.09.2012