Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 5.00/18: Рейтинг темы: голосов - 18, средняя оценка - 5.00
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602

Strict aliasing и memcpy

07.06.2017, 00:48. Показов 4541. Ответов 36
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Что-то я никак не врублюсь, как согласуются между собой strict aliasing и функции жонглирующие void*? Возьмем для примера memcpy. Стандартная оптимизация данной функции - копировать данные не отдельными байтами, а кусками побольше. Например, int-ами. Но для этого надо залезть через int* указатель в данные, которые вообще говоря могут и не являться массивом int. А strict aliasing такие фокусы запрещает. Однако, функция в стандарте есть. Так как она тогда в этот стандарт вписывается?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void*myMemcpy(void*dst,const void*src,std::size_t size)
{
    int*dstInt=reinterpret_cast<int*>(dst);
    const int*srcInt=reinterpret_cast<const int*>(src);
    for(;size>=sizeof(int);size-=sizeof(int))
        //строго следуя букве стандарта, здесь у нас UB
        //ведь никто не сказал что по адресу srcInt действительно лежит int
        *dstInt++=*srcInt++;
 
    char*dstChar=reinterpret_cast<char*>(dstInt);
    const char*srcChar=reinterpret_cast<const char*>(srcInt);
    for(;size;--size)
        *dstChar++=*srcChar++;
    return dst;
}
Ну и выдержка из стандарта:
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined: 52
— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type similar (as defined in 4.4) to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type
of the object,
— an aggregate or union type that includes one of the aforementioned types among its elements or non-
static data members (including, recursively, an element or non-static data member of a subaggregate
or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
— a char or unsigned char type.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.06.2017, 00:48
Ответы с готовыми решениями:

Каламбур типизации и strict aliasing
Есть ли какой-то стандартный способ обойти strict aliasing, с гарантией от UB? Конкретная задача: дан массив чисел. Требуется отсортировать...

Memcpy, buffer overflow. Может ли возникнуть ошибка в функции memcpy
Бывает ли на практике такое, что код #define size 1000; // some value int x, y; /* ... */ memcpy(y, x, (size + 1) * sizeof(int)); ...

Union, new placement, strict-aliasing, cross-platform
Доброго времени суток. Ниже представленный код вроде бы работает. Гонял его на компиляторах cl/mingw ...

36
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
09.06.2017, 12:56  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от IGPIGP Посмотреть сообщение
Я смогу относиться к strict aliasing с пониманием, только когда увижу адекватный код, в котором такая оптимизация уместна. Если у кого-то есть примеры, -покажите пожалуйста.
C++
1
2
3
++*a;//в момент инкремента, копия *a уезжает в регистр
*b=1;//возможно, здесь изменили и *a за компанию
return*a;//поэтому здесь *a придется читать заново, а не взять значение из регистра
И решается эта проблема давно уже придуманным в Си ключевым словом restrict ("данные по этому указателю ни с чем не пересекаются, инфа - соточка"). Только его никак в стандарт плюсов не перетащат.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
09.06.2017, 13:11
Цитата Сообщение от Renji Посмотреть сообщение
И решается эта проблема давно уже придуманным в Си ключевым словом restrict ("данные по этому указателю ни с чем не пересекаются, инфа - соточка"). Только его никак в стандарт плюсов не перетащат.
Тут вообще не понял. Если b указатель на a и имеет его тип (из текста не видно) то данный код совершенно корректен. strict aliasing запрещает писать по указателю на другой тип но по тому же адресу без возможных проблем.
В Вашем коде этого не видно. Всё вроде нормально. Если компилятор и тут имеет право, что-то не сделать, то осталось совсем немного до дурдома. Или я не прав?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
09.06.2017, 13:34
Цитата Сообщение от IGPIGP Посмотреть сообщение
Если компилятор и тут имеет право, что-то не сделать
Имеет право, если a и b указывают на одну и ту же область памяти. Компилятор посчитает, что ему незачем обращаться к памяти по адресу a повторно, если у него *a и так лежит в регистре. Вот только память-то изменялась в *b=1. То есть рассинхронизация того что в регистре и того что в памяти.
1
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
09.06.2017, 13:44  [ТС]
Цитата Сообщение от IGPIGP Посмотреть сообщение
Тут вообще не понял. Если b указатель на a и имеет его тип (из текста не видно) то данный код совершенно корректен. strict aliasing запрещает писать по указателю на другой тип но по тому же адресу без возможных проблем.
Если указатель a и b имеют разный тип, скорее всего запись в *b не влияет на *a. Но без strict aliasing такое предположить нельзя, а значит после *b=1 нужно перечитывать *a.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
09.06.2017, 14:42
Цитата Сообщение от TRam_ Посмотреть сообщение
Компилятор посчитает, что ему незачем обращаться к памяти по адресу a повторно, если у него *a и так лежит в регистре.
Хм... Но это же не обращение к одной и той же памяти по указателям разного типа. Это использование указателя по прямому назначению. Тут же если то что Вы говорите принять как аргумент, вообще нельзя будет работать с указателями и даже ссылками. То есть нельзя будет ссылаться на одну и ту же память из разных переменных.
Я читая того же Аксёнова понял, что именно различные по типу указатели на одну и ту же память могут быть разыменованы для записи без разыменования и записи. Дико это. И поэтому я попросил пример, который бы показывал, когда адекватный код, может быть ускорен такой оптимизацией без риска навредить тому кто такой код написал. То есть я хочу понять мотивы разрабов компиляторов.
Цитата Сообщение от Renji Посмотреть сообщение
Если указатель a и b имеют разный тип, скорее всего запись в *b не влияет на *a.
Почему? Если в коде указано напрямую, что есть обращение на запись?
Покажите мне пример, когда программист написал такое, для того чтобы оно было оптимизировано и не выполнено. Иначе создаётся впечатление, что авторы шепчут ( а в сишечке такого и нету, может туда лучше вернуться? ). Шучу.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
09.06.2017, 15:16
Чисто на всякий случай: restrict и strict-aliasing - это немного перпендикулярные вещи.

Strict-aliasing - это то, что исторически было раньше. Возможно, что исходили из того, что в реальной жизни указатели на разные типы данных в реальной жизни в 99.99% случаев не пересекаются. Поэтому нужно было что-то изобрести, чтобы компилятор в коде:

C
float *p1;
int *p2;
...
*p1 = ...
... = *p2;
мог переставить местами операцию чтения из памяти и операцию запись в память. Зачем это нужно я в своё время описывал тут: [Задача] Адресная арифметика. Вероятно, strict-aliasing и было тем изобретением, которое в большом количестве случаев позволяло load'ы перенести выше store'ов. Но со временем, вероятно, этого уже стало мало, а потому появились restrict'ы, как подсказка со стороны программиста, что два указателя смотрят на заведомо не пересекающиеся участки памяти. И всё это с той же самой целью - переставить load'ы как можно выше по исполнению, потому что во многих случаях это даёт приличный привар к скорости исполнения
2
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
09.05.2018, 17:41
Цитата Сообщение от Renji Посмотреть сообщение
Интерпретировать источник как массив char шибко накладно по времени.
Да и некорректно.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Во-первых, концептуально, функции типа memcpy переинтерпретируют исходные объекты, как массивы unsigned char. Это прямо разрешено правилами strict aliasing.
Есть мнение, что правила strict aliasing разрешают только кастить к указателю на (unsigned) char и читать/писать первый байт.
Арифметика указателей при этом не разрешена, т.к. этот указатель не указывает на элемент массива из (unsigned) char.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
09.05.2018, 23:37  [ТС]
Цитата Сообщение от rat0r Посмотреть сообщение
Есть мнение, что правила strict aliasing разрешают только кастить к указателю на (unsigned) char и читать/писать первый байт.
Тогда бы получилось что либо реализация std::istream::read злостно нарушает стандарт, либо что из файлов можно читать только char-ы.
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,038
Записей в блоге: 1
09.05.2018, 23:44
Цитата Сообщение от Renji Посмотреть сообщение
std::istream::read злостно нарушает стандарт
Библиотечные штуки могут делать что угодно без всяких нарушений.
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
10.05.2018, 00:14
Цитата Сообщение от Renji Посмотреть сообщение
Тогда бы получилось что либо реализация std::istream::read злостно нарушает стандарт
std::istream::read ничего сама не нарушает.
А вот программист может нарушить неправильным её использованием.
Цитата Сообщение от http://eel.is/c++draft/input.streams#istream.unformatted-itemdecl:12
basic_istream<charT, traits>& read(char_type* s, streamsize n);
Effects: Behaves as an unformatted input function (as described above). After constructing a sentry object, if !good() calls setstate(failbit) which may throw an exception, and return. Otherwise extracts characters and stores them into successive locations of an array whose first element is designated by s.
Отсюда можно сделать вывод, что в read можно совать только массив из символов и что указатель должен указывать на первый элемент массива.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
10.05.2018, 00:40  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Библиотечные штуки могут делать что угодно без всяких нарушений.
Вот только библиотечные штуки - просто обертка над std::streambuf::xsgetn, который быть библиотечным никому не обязан (перегруженная виртуальная функция).
Цитата Сообщение от rat0r Посмотреть сообщение
Отсюда можно сделать вывод, что в read можно совать только массив из символов и что указатель должен указывать на первый элемент массива.
Ну так и как прикажете читать из файла POD-объекты отличные от массива символов? Если никак, то зачем там тогда у файловых потоков бинарный режим чтения?
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
11.05.2018, 15:39
Цитата Сообщение от Renji Посмотреть сообщение
Ну так и как прикажете читать из файла POD-объекты отличные от массива символов?
А откуда в файлах вообще взялись объекты?

Цитата Сообщение от Renji Посмотреть сообщение
Если никак, то зачем там тогда у файловых потоков бинарный режим чтения?
Из стандарта C (т.к. стандарт C++ говорит, что binary mode соответствует модификатору "b" в stdio):
Цитата Сообщение от 7.21.2/3
A binary stream is an ordered sequence of characters that can transparently record
internal data. Data read in from a binary stream shall compare equal to the data that were
earlier written out to that stream, under the same implementation. Such a stream may,
however, hav e an implementation-defined number of null characters appended to the end
of the stream.
Вот за этим.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
11.05.2018, 19:11  [ТС]
Цитата Сообщение от rat0r Посмотреть сообщение
А откуда в файлах вообще взялись объекты?
Из оператора присваивания бессовестно примененного к отображенному в память файлу. Ах да, отображение файла в память, видимо, тоже нарушает стандарт.
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,038
Записей в блоге: 1
11.05.2018, 19:24
Цитата Сообщение от Renji Посмотреть сообщение
Ах да, отображение файла в память
В C++ нет такого.
Цитата Сообщение от Renji Посмотреть сообщение
тоже нарушает стандарт
Операционная система (и иже с ней) и компиляторы предоставляют определенные гарантии.
Им вообще пофиг на этот стандарт. У них свои правила.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
11.05.2018, 19:41  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Операционная система (и иже с ней) и компиляторы предоставляют определенные гарантии.
Компилятор про отображение файлов ничего не знает, для него это самая обычная не инициализированная память. Навигация в которой разумеется осуществляется через адресную арифметику с char*. Ну не указатели же в файле хранить, они при повторном отображении станут невалидны. Вот только rat0r адресную арифметику с char* считает нарушением strict aliasing, так что получается что пользователи отображения файлов в память стандарт злостно нарушают.
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,038
Записей в блоге: 1
11.05.2018, 20:15
Цитата Сообщение от Renji Посмотреть сообщение
Вот только rat0r адресную арифметику с char* считает нарушением strict aliasing
Он вообще не про strict aliasing. И для char*, как выше уже говорили - исключение в плане strict aliasing.
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
22.05.2018, 04:32
Цитата Сообщение от rat0r Посмотреть сообщение
Есть мнение, что правила strict aliasing разрешают только кастить к указателю на (unsigned) char и читать/писать первый байт.
Или я соврал. Даже чтение первого байта не гарантировано.
В общем, муть.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
22.05.2018, 04:32

Оптимизация кода, нарушающего правила strict aliasing
Доброго времени суток. Имеется такой код в ядре Linux: /* include/linux/netlink.h */ .... #define NETLINK_CB(skb) ...

warning: dereferencing pointer 't' does break strict-aliasing rules
Здравствуйте, уважаемые специалисты! К чему может привести данное предупреждение? Что нужно сделать, чтобы его не было? typedef...

SkyBox Anti-Aliasing
Здравствуйте Вот смотрю неплохую ссылочку. Все хорошо, понятно написано. Смущает вот это color = texture(skybox, R);Ну или вместо R...

Имитация anti-aliasing фотошопа средствами CSS
Граждане верстальщики, подскажите, есть ли средства в CSS сделать текст таким, как во-втором варианте? Изображение

Anti-aliasing Asus Rog Strix RX-480-08G Gaming
Всем привет! Всплыла проблема не корректной работы режимов сглаживания для видеокарты Asus Rog Strix RX-480-08G Gaming в некоторых...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
37
Ответ Создать тему
Новые блоги и статьи
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
rest api anylogic - выполнение модели на своём русском сайте
anaschu 02.07.2026
Как подружиться с AnyLogic Cloud API, победить провайдеров и развернуться Java-бэкенд в Docker на бесплатном хостинге: Двухдневный лог борьбы Всем привет! Хочу поделиться свежим (и довольно. . .
Где деньги лежат
kumehtar 02.07.2026
Это - японская подводная лодка I-52 (тип C2, кодовое имя Momi) вышла из Японии в марте 1944 года с миссией в оккупированную немцами Францию (Лорьян). Это была одна из «Янаги»-миссий по обмену. . .
Krabik для WoW 3.3.5a, многоязычный
AmbA 02.07.2026
Допилил бота, думаю что окончательно. Изменения: - добавлена многоязычность - добавлено снятие скриншотов - добавлено поддержание бафов хождения по воде (для жреца, дк и шамана) - и так, по. . .
Алиса нашла кучу ошибок компиляции и запуска в проекте, который без проблем компилировался и запускался)))
anaschu 30.06.2026
Я пока посмеюся, но завтра проверю. А вообще интерсно. Дал алисе файл, в котором точно нет ошибок компиляции и запуска, и попросил их найти. Нашла кучу))) Критические ошибки, мешающие компиляции и. . .
сукцессия 16. Общий обзор, в основном что бы другие ии поняли
anaschu 29.06.2026
# Передаточный документ: модель микоризной сукцессии (для нового чата) Этот документ предназначен для того, чтобы новый чат Claude мог продолжить работу без необходимости заново разбираться в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru