с такой, что memcpy прост как 3 копейки. это же простое копирование байт. выравнивание здесь по боку, оптимизатор тоже ничего не испортит. здесь просто нечему ломаться http://dbp-consulting.com/tutorials/StrictAliasing.html
Недавно была темка в std-discussion про memcpy.
Пришли к выводу, что подобное использование memcpy в C++ это UB, с C — неясно. Прямо указаний на определённое поведение нет, есть какие-то полунамёки.
ну вообще логично. memcpy внутри ведь тоже как-то кастует указатели, а значит там может всплыть то же самое нарушение strict aliacing. возиться с байтами в цепепе себе дороже. если и в сишке такая же порнография - это вообще атас. «кроссплатформенный ассемблер», где простейшая операция с байтами любыми способами сводится к UB, бгг
ну вообще логично. memcpy внутри ведь тоже как-то кастует указатели, а значит там может всплыть то же самое нарушение strict aliacing.
memcpy это библиотечная функция, на неё не распространяются никакие правила. Она работает так, как определено стандартом. Даже если ты посмотришь в её реализацию и увидишь там возможные нарушения.
ну в цепепе охотно верится (хотя впервые слышу). а в сишке уверен, что нет. memcpy так юзают повсеместно. даже в примерах документации копируют int64_t в double и не чешутся
отличие очень простое:
1. код в посте, согласно документации - не валиден
2. код с memcpy, согласно документации - валиден
документация прямо разрешает юзать memcpy как раз в таких вот случаях, как в посте:
Where strict aliasing prohibits examining the same memory as values of two different types, memcpy may be used to convert the values.
поэтому нет видимых оснований считать код c memcpy UB (случаи UB для memcpy там тоже указаны и ничего про типы там нет)
ну либо доку пишут диверсанты, которые хотят, чтобы разработчики отстреляли себе не только ноги, но и яйца, а сишка не пригодна для банальных байтовых операций от слова совсем
p/s. цитата касается си, как там с этим в цепепе не знаю
Сам ты наркоман! Это — нормально! Единственный косяк — не забывать о «конечности», и если на тупоконечной машине это будет запускаться, возможно, не пройдет. Поэтому UB. Но элементарные операции преобразования помогут.
Поскольку ваше утверждение первое, то начинать вам
Твои детсадовские методы тут не пройдут. UB — отсутствие определённого поведения. Отсутствие доказать невозможно, кроме как тем фактом, что определение поведения не предъявлено.
Так что расписывай поведение со ссылками на стандарт или оно автоматически не определено.
1. код в посте, согласно документации - не валиден 2. код с memcpy, согласно документации - валиден
Какая документация во втором случае? Если в первом случае стандарт, то во втором — мнение частного лица.
нет видимых оснований считать код c memcpy UB
Видимых — это чтобы компилятор делал что-то неожиданное с кодом с UB в подобном коде? Да, таких случаев я не знаю. И не утверждал, что они есть. К тому же, я сказал, что насчёт C до конца не ясно, что там UB. Вроде есть полунамёки, что так можно, но они очень косвенные.
а сишка не пригодна для банальных байтовых операций от слова совсем
Ну как бы да. Даже читать из неактивного члена union-а в стандарте C разрешает подстрочное примечание. А как известно, подстрочные примечания не нормативны (не являются правилами). Если так понимать, то читать из неактивного члена union UB не только в C++, но и в C. Хотя бытует мнение, что в C это где-то разрешено.
Какая документация во втором случае? Если в первом случае стандарт, то во втором — мнение частного лица.
http://en.cppreference.com/w/c/string/byte/memcpy
Утверждение логично следует из куска стандарта, который привели
выше. Видимо, уже не раз задавались этим вопросом, вот и вписали
Прямого разрешения в стандарте, конечно, не найти. Хотя бы потому что стандарт не может предусмотреть все возможные варианты использования и регламентировать каждый чих. Стандарт просто задает правила, а задача программиста стараться их не нарушать.
Вроде есть полунамёки, что так можно, но они очень косвенные
В одном случае прямое указание на нарушение, в другом косвенные полунамеки. Выбор очевиден, потому что операцию все равно надо как-то выполнять. Остается довериться здравому смыслу, либо вообще бросить си. Так как по такой логике UB можно заподозрить в чем угодно
Утверждение логично следует из куска стандарта, который привели выше.
В C++ есть точно такой же кусок про aliasing. При этом не считается, что он разрешает делать memcpy между объектами разных типов. Более того, считается, что явное описание поведения memcpy между объектами одного и того же trivially copyable типа (http://eel.is/c draft/basic.types#2 и http://eel.is/c draft/basic.types#3) говорит о том, что в других случаях поведение не определено.
Местом, которое размыто намекает, что memcpy в C делать можно (т.е. есть какие-то способы изменения значения объекта кроме как через lvalue типа этого объекта) это:
6.2.6.1/5
Certain object representations need not represent a value of the object type. If the stored
value of an object has such a representation and is read by an lvalue expression that does
not have character type, the behavior is undefined. If such a representation is produced
by a side effect that modifies all or any part of the object by an lvalue expression that
does not have character type, the behavior is undefined. 50) Such a representation is called
a trap representation.
стандарт не может предусмотреть все возможные варианты использования и регламентировать каждый чих
Да. Для этого ввели понятие неопределённого поведения:
3.4.3/1
behavior, upon use of a nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements
4/2
If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime-
constraint is violated, the behavior is undefined. Undefined behavior is otherwise
indicated in this International Standard by the words ‘‘undefined behavior’’ or by the
omission of any explicit definition of behavior. There is no difference in emphasis among
these three; they all describe ‘‘behavior that is undefined’’.
И если стандарт не описал какой-то чих, сиди гадай, это UB или надо высасывать из какого-то пальца определение этого поведения. (Меня, например, 6.2.6.1/5 не особо убеждает что memcpy определён, я могу и другие интерпретации подобрать к этому параграфу).
Если адрес выровнен и код будет только на узкоконечной архитектуре запускаться, то никакого UB не будет. Но если автор решит перенести это на тупоконечную, или же адрес вдруг будет не выровнен, начнутся приколы.
Так что, больше UB, нежели хорошо.
Я уже разгребал чужой код, писанный под 32-битную архитектуру с использованием всяких сволочных char'ов, int'ов и long'ов вместо нормальных int8_t и т.п. Дня три убил, пока оно у меня на 64-битной архитектуре взлетело. Сам тоже натыкался на косяк: использовал ассемблерные вставки для оптимизации кода, в итоге оно на ARM'ах компиляться отказывалось. Боюсь, если вдруг мне попадется тупоконечная машина, то подавляющая часть моего быдлокода вообще откажется собираться, либо же будет сплошное UB…
В C++ есть точно такой же кусок про aliasing. При этом не считается, что он разрешает делать memcpy между объектами разных типов.
Значит в крестах есть что-то такое, что не позволяет полностью полагаться на п.6.5.7 в данном вопросе. Надо спрашивать у тех кто так не считает
Насколько я понимаю, в memcpy каждый символ интерпретируется, как unsigned char. А unsigned char может быть псевдонимом любого типа. Поэтому передача в memcpy данных разных типов, либо типов, отличных от unsigned char вполне законна и она выполнит работу, как надо
Проблемы могут быть с последующим использованием скопированных данных. Допустим программист не учел порядок байт и получил в size_pic совсем не то, что хотел. Вполне себе неопределенное поведение. Но это не траблы с выравниванием и не нарушение strict aliasing, последствия такого UB можно исправить в самом коде