почему волатильность меняет тип?
От: Kubyshev Andrey  
Дата: 02.10.14 11:51
Оценка:
Привет,

Visual studio 9:

volatile char buffer[16];
memcpy (buffer,0,17);

Получаем ошибку 'memcpy' : cannot convert parameter 1 from 'volatile char [16]' to 'void *'
Почему волатильность это тип ? Я думал это хинт оптимизатору.
Re: почему волатильность меняет тип?
От: denisko http://sdeniskos.blogspot.com/
Дата: 02.10.14 12:02
Оценка:
Здравствуйте, Kubyshev Andrey, Вы писали:

Это прежде всего, как и конст, указание тебе на то, чтобы ты подтвердил, что ты понимаешь что делаешь.
<Подпись удалена модератором>
Re: почему волатильность меняет тип?
От: watchmaker  
Дата: 02.10.14 12:07
Оценка: 9 (2)
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Почему волатильность это тип ? Я думал это хинт оптимизатору.

Совсем нет. Это не подсказка оптимизатору — это обязательное требование. Причём одно из самых важных с точки зрения реализации.
В стандарте (я приведу С++2003, так как там формулировки короче) в самом начале:

1.9 Program execution
[intro.execution]
1 The semantic descriptions in this International Standard define a parameterized nondeterministic abstract
machine. This International Standard places no requirement on the structure of conforming implementa-
tions. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conform-
ing implementations are required to emulate (only) the observable behavior of the abstract machine as
explained below


6 The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and
calls to library I/O functions.


То есть компилятор обязан соблюдать всего две вещи: сохранять последовательность I/O и работу с volatile. А весь остальной стандарт — это просто уточнение к тому, как сохранять эти две вещи :) Его допустимо даже не реализовывать полностью, если компилятор сумеет добиться такого же поведения с I/O и volatile каким-либо другим магическим способом :)
Отредактировано 02.10.2014 12:38 watchmaker . Предыдущая версия .
Re[2]: почему волатильность меняет тип?
От: Vain Россия google.ru
Дата: 02.10.14 16:52
Оценка:
Здравствуйте, denisko, Вы писали:

D>Это прежде всего, как и конст, указание тебе на то, чтобы ты подтвердил, что ты понимаешь что делаешь.

Да, но на практике выходит, что тебе постоянно приходится это делать. Я не хочу сказать, что это плохо само по себе, просто с волейтайл это перебор. Чтобы заставить код компилироваться с волейтал, мне приходиться поддерживать по паре функций/классов/<нужное вставить>, а сконст это ещё на два умножает. Из-за этого код превращается в оверблоат лажу. Хотели как лучше, а получили — как всегда.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: почему волатильность меняет тип?
От: Kubyshev Andrey  
Дата: 03.10.14 03:43
Оценка:
Ну а почему вдруг при volatile memcpy не пожет сам преобразовать массив к типу void * ?
Re[3]: почему волатильность меняет тип?
От: Alexander G Украина  
Дата: 03.10.14 06:26
Оценка: 13 (3)
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Ну а почему вдруг при volatile memcpy не пожет сам преобразовать массив к типу void * ?


memcpy с не-volatile указателями имеет право "халтурить", в частности, не делать вообще ничего, если результат не используется.

если бы memcpy работала бы c volatile, должна была бы читать и писать всегда по-настоящему.

есть случай, правда в WinAPI и с memset, а не с memcpy, когда оба варианта есть, это ZeroMemory и SecureZeroMemory.
ZeroMemory — обёртка над memset, если будем так обнулять более не используемые переменные, это может быть выоптимизировано.
SecureZeroMemory — явная запись через volatile, рекомендуется для обнуления буфера с sensitive информацией.

Вот, было бы странно, что преобразование к халтуре было бы неявным. В случае явного
volatile char buffer[16];
memcpy ((volatile char*)buffer,src,17);

делая такой каст, снимаешь с компилятора ответственность, теперь он имеет право выкинуть memcpy, если далее buffer не нужен.
Русский военный корабль идёт ко дну!
Re: почему волатильность меняет тип?
От: ML380 Земля  
Дата: 03.10.14 06:49
Оценка:
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Почему волатильность это тип ? Я думал это хинт оптимизатору.


Нет, волатильность позволяет даже перегружать функции (так же, как и константность).
Re: почему волатильность меняет тип?
От: flаt  
Дата: 03.10.14 08:04
Оценка:
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Почему волатильность это тип ? Я думал это хинт оптимизатору.

Тут ещё разница между "volatile void*" и "void* volatile" http://melpon.org/wandbox/permlink/kSV8ioWK8oMMLPkB

В первом случае указатель на другой тип (как и const void*), во втором — спецификатор указателя (как и void* const — "хинт")
Re[3]: почему волатильность меняет тип?
От: watchmaker  
Дата: 03.10.14 08:21
Оценка: 36 (6)
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Ну а почему вдруг при volatile memcpy не пожет сам преобразовать массив к типу void * ?

А зачем так делать? Это будет вредно или что-нибудь сломает.

volatile память — это даже не всегда память, и будет ошибкой работать с ней так же как и с массивом на куче . Например volatile может использоваться для MMIO — в этом случае за переменной или массивом скрывается устройство и работа идёт с его регистрами. Если в коде написано volatile uint8_t* r = ...; *r = 10; *r = 20;, то это означает передать устройству сначала байт 10, потом байт 20. Если убрать volatile, то компилятор может, например, выкинуть запись 10 в память, ведь в памяти это значение всё равно перезапишется числом 20, а значит его сразу и стоит писать. Но устройство — не память, для него такое выкидывание означает катастрофу — потерялся байт!
А это всего одна однобайтовая переменная. А что должен делать memcpy с volatile памятью? Копировать её, но в каком порядке? Или какими блоками? Или насколько делать prefetch? Что должно сделать устройство, если оно ожидает массив байт, а memcpy будет записывать блоками в 128 раз большими, да ещё идя в обратном направлении от старших адресов к младшим (как делают некоторые быстрые реализации memcpy на x86-64 архитектуре)?
Тут единственный вариант сделать memcpy совместимой c volatile памятью — это жестко прописать в стандарте как работает эта функция на всех платформах и архитектурах. Что впрочем сделает её сразу же бесполезной — почти всегда никому не нужно универсальное, но невероятно медленное копирование, для которого которого жестко зафиксировано, например, что оно всегда идёт только по char'ам, только в сторону увеличения адресов, никогда не накапливает внутри себя более одного char'а (это ведь тоже может быть важно, если вдруг мы копируем из устройства в устройство). Причём дальше всё равно выяснится, что и для работы с устройствами такая функция также обычно не нужна, а нужен какой-нибудь Duff's device.


Посмотри что выше написано в стандарте — там ведь содержится очень простая идея — важен результат работы программы (то есть работа с I/O и с volatile, которые например устройства), и не важно как работает внутри программа — это вообще может быть чёрный ящик. И если два ящика дают одинаковые реакции, то стандарту удовлетворяют оба. А на остальной тысячи страниц описано как сделать ящик-образец, с которым можно сравниваться, но который не обязательно делать. И вся не-volatile память — она находится строго внутри, её не видно снаружи и компилятор не обязан даже её выделять когда написан malloc (поведение и саму возможность существования отладчиков, способных заглянуть внутрь, стандарт не описывает) — вот пример (выбрать компилятор clang 3.3, если автоматически не выбрался).
В некотором смысле ты был прав, когда назвал volatile "хинтом оптимизатору" — вот только эта подсказка относится не к самой переменной, а ко всей остальной программе — и компилятор, например, может выкинуть из неё кусок (и иногда так и делает) или заменить один алгоритм на другой (тоже иногда получается), если сумеет доказать что это не повлияет на volatile и I/O.

Относись к volatile не как к "ещё одному const", а как к интерфейсу между внешним миром и программой на C/C++. И нечего нагружать функцию memcpy знаниями об этом мире :)
Отредактировано 03.10.2014 23:03 watchmaker . Предыдущая версия . Еще …
Отредактировано 03.10.2014 21:05 watchmaker . Предыдущая версия .
Re[4]: почему волатильность меняет тип?
От: кубик  
Дата: 03.10.14 15:59
Оценка:
watchmaker, чисто для информации, а сколько у тебя опыт работы 7
Re: почему волатильность меняет тип?
От: Mr.Delphist  
Дата: 03.10.14 16:12
Оценка:
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Почему волатильность это тип ? Я думал это хинт оптимизатору.


Волатильность — это не хинт, а квалификатор типа. Такой же как const. Не случайно в Стандарте они даже упоминаются вместе: cv-qualification
http://en.cppreference.com/w/cpp/language/cv
Т.е. корректное использование квалификаторов позволяет программисту более точно обрисовать сценарий использования (и отловить часть ошибок сразу на этапе компиляции). А уж как именно компилятор решит всё это оптимизировать — полностью его дело.
Re: почему волатильность меняет тип?
От: BulatZiganshin  
Дата: 12.10.14 22:33
Оценка:
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Почему волатильность это тип ? Я думал это хинт оптимизатору.


void f (int &i)  {while(i);}

volatile i=1;
f(i);
Люди, я люблю вас! Будьте бдительны!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.