Допустимые случаи использования для reinterpret_cast для невыровненного доступа к памяти против memcpy?

Во внутренностях snappy есть условно скомпилированный раздел, который выбирает разыменование reinterpret_cast’ed указатель как лучшая реализация для чтения и записи потенциально невыровненных 16, 32 и 64-битных целых чисел на архитектурах, которые, как известно, поддерживают такие операции (например, x86). Откат для других архитектур состоит в том, чтобы использовать реализация на основе memcpy.

Насколько я понимаю, реализация reinterpret_cast демонстрирует неопределенное поведение, а неопределенное средство поведения clang помечает его.

Что меня удивляет, так это почему бы просто не использовать реализацию, основанную на memcpy? Я ожидал бы, что все, кроме самого сломанного компилятора, будут использовать встроенные функции для реализации этих вызовов memcpy, так как размер известен во время компиляции. Фактически, я ожидал бы идентичный кодген от обеих реализаций на любом современном наборе инструментов.

Тем не менее, я также признаю, что snappy был написан людьми, которые знают, о чем они. Так что это заставляет меня задуматься о том, есть ли еще какое-то преимущество в использовании механизма reinterpret_cast, который перевешивает его неопределенное поведение. Не хотите, чтобы производительность зависела от качества реализации компилятора? Что-то еще я не учел?

5

Решение

Не зная программистов, которые написали этот код, я сомневаюсь, что вы можете получить действительно авторитетный ответ.

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

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

3

Другие решения

Причина в том, что быстрее (на x86) загрузить int с невыровненного адреса, чем скопировать его и затем загрузить.

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

Лично я бы реализовал безопасный метод как 4-байтовые нагрузки со сдвигами.

-1

По вопросам рекламы [email protected]