Здравствуйте, maks1180, Вы писали:
M>Почему он значения dst зависит вперёд или назад копировать, я не пойму...
memcpy копирует байты. Желание ускорить копирование вполне естественно.
Одна из очевидных оптимизаций — копировать байты параллельно. Лет двадцать назад я посмотрел под отладчиком как выглядит код зануления структуры в памяти. Вместо rep stosb я увидел одну MMX инструкцию, одну инструкцию для математического сопроцесора, одну AVX инструкцию и пару обычных. Зачем такие сложности? А затем, что все эти инструкции процессор обрабатывает параллельно. Аналогично с копированием. Если копирование можно распараллелить, то его можно ускорить. При этом порядок, в котором байты попадают из src в dst в общем виде будет не определён.
вызываю memcpy(dst, src, len), где src=dst+58, len=137. dst всегда кратен 16.
Т.е. диапазоны перекрываются, но так как src больше чем dst, поэтому я думал проблем ну будет.
Но вышла проблема, причём самое интересное, что проявляется переодически.
Заметил, что когда dst заканчивается на D0,E0,F0 проблема есть. Т.е. 3 из 16 раз.
Пытался посмотреть исходники memcpy, понял что он копирует вперёд (т.е. увеличивая поинтеры), но я не понял почему оно зависит от адреса dst и почему вообще проблема существует если идёт вперёд при копировании.
Здравствуйте, maks1180, Вы писали:
M>Пытался посмотреть исходники memcpy, понял что он копирует вперёд (т.е. увеличивая поинтеры), но я не понял почему оно зависит от адреса dst и почему вообще проблема существует если идёт вперёд при копировании.
Может стоить взять memmove? И не выдумывать вот это вот всё, просмотр отладчиком как работает rep movsb
Здравствуйте, maks1180, Вы писали:
_>>Замените на std::memmove
M>Это понятно, просто хотел разобраться как работает memcpy
А какой смысл, если оно меняется с платформой и компилятором да еще и от фазы луны может зависеть?
Если оно UB то чудеса могут быть такие что хоть обсмотрись исходников, грабли которые компилятор разложит там не видно.
Здравствуйте, maks1180, Вы писали:
M>Это понятно, просто хотел разобраться как работает memcpy
Надо смотреть не исходники, а скомпилированный код. Компилятор может заменить вызов memcpy на цикл, например. Также memcpy может быть в куче вариантов и какой там скомпилируется — не разберёшься. В общем надо отладчиком лезть и в дизассемблер смотреть, благо memcpy штука небольшая.
Здравствуйте, maks1180, Вы писали:
M>Смысл разобраться, что-бы понимать что под капотом memcpy твориться, может что нового для себя подчерпнуть. https://www.youtube.com/watch?v=mmnWSkwF7KQ
Здравствуйте, maks1180, Вы писали:
M>вызываю memcpy(dst, src, len), где src=dst+90, len=137. dst всегда кратен 16. M>Т.е. диапазоны перекрываются, но так как src больше чем dst, поэтому я думал проблем ну будет. M>Но вышла проблема, причём самое интересное, что проявляется переодически. M>Заметил, что когда dst заканчивает на B0,С0,D0 проблема есть. Т.е. 3 из 16 раз.
M>Пытался посмотреть исходники memcpy, понял что он копирует вперёд (т.е. увеличивая поинтеры), но возможно кусочек начала копирует в конце поэтому и проблема, M>но я не понял почему оно зависит от адреса dst.
Здравствуйте, maks1180, Вы писали:
M>Смысл разобраться, что-бы понимать что под капотом memcpy твориться, может что нового для себя подчерпнуть.
Что за бред? Под капотом там может творится всё что угодно.
M>Кажется простая функция, а нарвался на неприятности, обидно что в релизе клиенты нашли.
Функция простая, просто не надо её использовать для того, для чего она не предназначена, и будет тебе счастье.
M>По анализам полученных данных после memcpy, подходит версия, что он иногда копирует от конца к началу данные, а не вперёд, вот тогда и начинаются проблемы. M>Почему он значения dst зависит вперёд или назад копировать, я не пойму...
Может, просто почитать стандарт, и зазубрить, что memcpy даёт UB при перекрытии src и dst?
M>Пытался посмотреть исходники memcpy, понял что он копирует вперёд (т.е. увеличивая поинтеры), но я не понял почему оно зависит от адреса dst и почему вообще проблема существует если идёт вперёд при копировании.
Ты наверное нашел не те исходники, их много, своя под каждую платформу, иногда своя под каждые возможные фичи процессора, вот например одна из возможных (выбираемых в рантайме) реализаций https://github.com/bminor/glibc/blob/master/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S
И это только вариации для x86-64
Как много веселых ребят, и все делают велосипед...
_>А какой смысл, если оно меняется с платформой и компилятором да еще и от фазы луны может зависеть? _>Если оно UB то чудеса могут быть такие что хоть обсмотрись исходников, грабли которые компилятор разложит там не видно.
Смысл разобраться, что-бы понимать что под капотом memcpy твориться, может что нового для себя подчерпнуть.
Кажется простая функция, а нарвался на неприятности, обидно что в релизе клиенты нашли.
По анализам полученных данных после memcpy, подходит версия, что он иногда копирует от конца к началу данные, а не вперёд, вот тогда и начинаются проблемы.
Почему он значения dst зависит вперёд или назад копировать, я не пойму...
Здравствуйте, maks1180, Вы писали:
M>вызываю memcpy(dst, src, len), где src=dst+58, len=137. dst всегда кратен 16. M>Т.е. диапазоны перекрываются, но так как src больше чем dst, поэтому я думал проблем ну будет.
Это, конечно, недоработка со стороны разработчиков компиляторов C/C++. Undefined Behaviour зачастую сходит с рук незамеченным. Должно было бы сделано так: за каждый случай UB, прошедший review и тестирование у кого-нибудь из причастных на кухне убегает молоко или протекает унитаз.
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, пффф, Вы писали:
П>>Может, просто почитать стандарт, и зазубрить, что memcpy даёт UB при перекрытии src и dst?
Pzz>Интересно, а кто-нибудь из присутствующих читал стандарт? Вот прям именно стандарт, а не его пересказ человеческими словами?
7.24.2 Copying functions
7.24.2.1 The memcpy function
Synopsis
1 #include <string.h>
void *memcpy(void * restrict s1,
const void * restrict s2,
size_t n);
Description
2 The memcpy function copies n characters from the object pointed to by s2 into the
object pointed to by s1. If copying takes place between objects that overlap, the behavior
is undefined.
Returns
3 The memcpy function returns the value of s1
Мне правда было интересно, читают ли в среднем люди стандарты, или находят их на интернете в "переваренном" виде.
П>Извини, не UB, а the behavior is undefined
П>>Извини, не UB, а the behavior is undefined
Pzz>А это не одно и то же?
Неопределенное поведение, или поведение не определено? С точки зрения обычного человека, оно конечно одно и то же, но я давно понял, что стандарты, особенно плюсовые, пишут рептилоиды, так что не факт.
Здравствуйте, пффф, Вы писали:
Pzz>>А это не одно и то же?
П>Неопределенное поведение, или поведение не определено? С точки зрения обычного человека, оно конечно одно и то же, но я давно понял, что стандарты, особенно плюсовые, пишут рептилоиды, так что не факт.
Там же вроде есть термины implementation-defined/unspecified/undefined behaviour, и они прям термины-термины, как MUST/MAY/SHOULD в RFC.
Так что behaviour undefined вроде как должно быть то же самое, что undefined behaviour, не?
Про рептилоидов согласен
Что интересно, сетевые RFC на заре цивилизации писали люди, и их прям можно было читать, а потом людей вытеснили рептилоиды, и читать их стало сложно.
Здравствуйте, maks1180, Вы писали:
M>Это понятно, просто хотел разобраться как работает memcpy
Зависит от реализации конкретного компилятора, как понимаю, а он использует какие-то функции из ОС (WinAPI, системные вызовы POSIX и др.).
Для перекрывающихся областей всегда необходимо использовать memmove, оно для того и придумано.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
Здравствуйте, Pzz, Вы писали:
Pzz>Мне правда было интересно, читают ли в среднем люди стандарты, или находят их на интернете в "переваренном" виде.
Многие стандарты платные. Слишком много чести кормить тунеядцев и социальных паразитов.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
The memcpy() function copies n bytes from memory area src to memory area dest. The memory areas must not overlap. Use memmove(3) if the memory areas do overlap.
Здравствуйте, Pzz, Вы писали:
Pzz>Это, конечно, недоработка со стороны разработчиков компиляторов C/C++.
Непонятно, почему это вообще должно парить разработчиков компилятора.
Это документированное поведение функции memcpy. Если некто неправильно ее использует, это его проблемы.
А то может вообще требовать от компилятора обнаруживать все потенциальные баги?
Тогда это уже не C/C++ надо, а доказательное программирование.