LINUX.ORG.RU

Квалификатор volatile в c и c++

 , ,


0

2

Вот здесь есть один интересный момент, а именно: автор утверждает, что volatile имеет эффект только при объявлении/определении объекта, но не имеет эффекта в случае обращения через указатель, получаемый в результате операции вида const_cast<volatile T*>(t)(в предположении что t объявлен как T* t = ...;). В комментариях срач, и не слишком ясно как обстоит дело на самом деле. Что вы думаете по этому поводу?

Deleted

Проверяй сам, не слушай дебилов на форумах. 95% из них стандарт в глаза не видели, и ассеблерный вывод не читали.

По теме правы те, кто говорит что эффект есть, вот мой тест

https://godbolt.org/g/58m5Ec

fsb4000 ★★★★★
()

volatile — это свойство выражения (хоть исходного, хоть промежуточного). Если выражение включает в себя объект в этим квалификатором, то он имеет эффект. И не важно берётся ли volatile значение от типа переменной, в результате разименования указателя или от каста.

xaizek ★★★★★
()
Ответ на: комментарий от fsb4000

Насчёт проверки: ищу в стандарте(ЧСХ, пока не нашёл). Проверять существующие реализации смысла пока не вижу, т. к.:

  • по понятным причинам нет четких правил, предписывающих компилятору провести оптимизацию. Другими словами, даже на неверном по стандарту коде, компилятор может «компенсировать» криворукость
  • интересна именно позиция стандарта
Deleted
()
Ответ на: комментарий от xaizek

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

7.1.6.1 The cv-qualifiers
4 Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.
[ Example:
int i = 2;
const int* cip(&i);
int* ip = const_cast<int*>(cip);
*ip = 4; // defined: *ip points to i, a non-const object

в примере снятие const, согласно утверждению выше - UB, но на самом деле нет. Получается, некоторые свойства объектов всё же зависят только от объявления/определения

Deleted
()
Ответ на: комментарий от Deleted

Зависят в том смысле, что с объектом нельзя сделать что-то, что не разрешено для памяти, в которой он может быть выделен. В случае с volatile UB будет при не-volatile доступе к volatile объекту. А для не-volatile объекта volatile квалификатор можно сколько угодно раз добавлять/убирать и он будет иметь эффект, если его добавить даже к не-volatile объекту.

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

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Хорошо, спасибо за разъяснения. В стандарте только это нашёл:

1.9 Program execution
12 Accessing an object designated by a volatile glvalue (3.10), [...] are all side effects, which are changes in the state of the execution environment

Думаю, достаточно. Остальное можно на неоднозначности в формулировках списать

Deleted
()
Ответ на: комментарий от fsb4000

Дебилы на форумах - это те кто проверяет свойства языка тестами.

anonymous
()
Ответ на: комментарий от Deleted

В стандарте только это нашёл
Думаю, достаточно.

Более чем. Говорится про glvalue, а glvalue это класс выражений.

anonymous
()

на самом деле, volatile имеет эффект лишь в той области, где компилятор его видит. и он не оптимизирует такие обращения, если в области видимости объект не изменяется. предполагается, что объект может быть изменён снаружи кода, который оптимизируется. если объект изначально не был объявлен, как volatile, компилятор может оптимизировать код как ему заблагорассудится в тех блоках, где он не видит квалификатора volatile.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

на самом деле, volatile имеет эффект лишь в той области, где компилятор его видит.

Поражающая своей глубиной мысль.

А ещё функции объявляются там, где компилятор видит их объявление.

anonymous
()
Ответ на: комментарий от anonymous

Суть в том, что я вырезал из цитаты вот эту часть:

modifying an object, calling a library I/O function, or calling a function that does any of those operations

Модификация объекта сама по себе side-эффектом не является. Поэтому утверждать не буду

Deleted
()

Автор потуги - малоразвитый колхозник, который нихрена не зная пытается нести ахинею и делать какие-то выводы.

Все эти рассуждения колхозников сводятся к тому, что это жертвы убогой макулатуры. Они где-то прочитали ахинею, не поняли её и начинают эту ахинею ретранслировать, ведь надо показывать публике свою осведомлённость.

В частности, подобные эксперты не могут понять разницу между volatile и отсутствием оптимизации. Они прочитали где-то о том, что volatile отключает какую-то неведомую оптимизацию, только вот они не поняли, что оптимизация частная и оптимизация в целом - это совершенно разные вещи.

Не читал эту ахинею, но:

На самом деле – имеет. Стандарт говорит, что последовательность чтения-записи должна сохраняться только для данных с квалификатором volatile. Вот для таких:

Причина этому банальна – это «не нужно».

Явные проблемы. Причина проста - человек не нашел своё призвание и попал не на своё место.

Если мы предположим, что авторы стандарты не идиоты, то такой ахинею там попросту не может быть. Ведь никакого понятия «данных» в си нет. Что нам делать с хипом? Как нам задать им квалификатор? Зачем нам задавать квалификаторы для автоматической, стековой памяти? Которую попросту невозможно пошарить и повесить на неё левую логику.

vcerloman
()
Ответ на: комментарий от vcerloman

Привет, царь. Авторы стандарта, разумеется не идиоты, но ошибки у всех бывают. Вот пример из этой серии. Я, собственно, уточнить зашел.

P. S.

А все их [недоязычков] адепты моют полы

Эпично!

Deleted
()
Ответ на: комментарий от Deleted

Всё очень просто - колхозники не понимают логики языка, хотя её зачастую не понимают и авторы стандарта, ведь они зачастую такие же колхозники( привет Страуструп).

На самом деле всё просто. Если ты поймёшь что такое type * ptr, и поймёшь, что типом является *, а так же то, что void - не является типом. Хотя этот факт написан в стандарте, но в любом случае.

Колхозники никогда себе не задавали вопроса - как частью типа может быть void, который не тип? И тогда бы им ничего не мешало бы понять то, что в type * ptr - типом является *.

То, что стоит слева от * является типом для результата операции *, а теперь подумай - имеет ли отношение квалификатор доступа к операции доступа? И ответ ты получишь.

Именно поэтому колхозники и ноют, что они не понимают того, почему там два конста(и других квалификаторов). Почему const type * ptr - не имеет никакого отношения к ptr.

В этом заключается фундаментальная проблема подобных адептов. Они либо не пытаются, либо попросту не способны понять банальную логику построения тех конструкций, которые они используют.

За этим даже далеко ходить не надо - ведь функция обладает той же логикой.

Понимая это - тебе станет понятно как и почему работает то, что ты спастил с констом. Хотя даже тут комментарии писал колхозник, ведь *ip - не имеет никакого отношения к i. И никаким поинтером на i не является. Подобная ахинея и путает людей.

vcerloman
()
Ответ на: комментарий от Deleted

Авторы стандарта, разумеется не идиоты

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

На самом деле надо брать пример с со всех остальных, мир С/С++ слишком сильно упарывается по стандартам. В основном это форсят всякие малоразвитые колхозники, которые сидят и зубрят стандарт. Я нихрена не могу, но стандарт заучил. Я ведь не могу признать в том, что я мусор? Надо форсить установку «заучивание стандарта == понимания языка, умения в язык».

Это попросту не имеет смысла, ведь никто и никогда этот стандарт не зазубрит, даже самые буйные адепты. Именно поэтому стандартам можно и нужно в 90% случаев подтираться.

Что-то работает каким-то образом? Ты понимаешь почему? Этого достаточно. Это либо соответствует стандарту, либо авторы компилятора им подтёрлись. В любом из случаев - стандарт тебе не нужен.

Стандарт нужен тогда, когда есть прям совсем упоротая логика, т.е. когда что-то работает так лишь потому, что какой-то васян захотел, чтобы это так работало. При этом это «хотел» не основано ни на чём, а просто на рандом позыве левой пятки васяна.

vcerloman
()
Ответ на: комментарий от Deleted

Модификация объекта сама по себе side-эффектом не является.

Как ты сумел сделать такой гениальный вывод из простого предложения, где прямо говорится, что модификация объекта — это сайд-эффект?

anonymous
()
Ответ на: комментарий от vcerloman

колхозники не понимают логики языка, хотя её зачастую не понимают и авторы стандарта

Не буду столь категоричным, многие тонкости сделаны, всё таки, по уму(внимание на правило вывода из prvalue).

void - не является типом

Это удобное обобщение. Напимер:

void g();
void f() { return g(); }
Если не рассматривать void как тип, в правилах появится исключение. Простое, но оно запутывает дело. Ну и да, функция по определению должна что-либо возвращать, а процедур как в pascal-е в c нет(и это решение, на мой взгляд, лучше) - так что пример можно даже упростить.

*ip - не имеет никакого отношения к i

Здесь не согласен. Оба выражения: i и *ip представляют собой обращение к одной и той же ячейке памяти

Deleted
()
Ответ на: комментарий от Deleted

Не буду столь категоричным, многие тонкости сделаны, всё таки, по уму(внимание на правило вывода из prvalue).

Just curious, чем тебе так понравилось правило вывода для prvalue?

anonymous
()
Ответ на: комментарий от anonymous

Серьёзно? Ну объясни мне тогда, почему компилятор выпиливает, например, такое:

int main()
{
    int x[10];
    for (auto& i:x) i=0;
}
Выхлоп:
0000000000000560 <main>:
 560:   31 c0                   xor    %eax,%eax
 562:   c3                      retq

Deleted
()
Ответ на: комментарий от vcerloman

Что-то работает каким-то образом? Ты понимаешь почему? Этого достаточно

Э не... Была уже тема(да ещё какая, ты наверное, тоже там был), где главной ошибкой был как раз ничем не обоснованный спуск на физический уровень и попытки представить во что скомпилируется тот или иной код. Fail

Deleted
()
Ответ на: комментарий от anonymous

чем так понравилось

Ну если не мудурствуя выводить T&& вместо T, вот такое, скорее всего, порвалось бы

std::string g();
decltype(auto) f() { return g(); }

Deleted
()
Ответ на: комментарий от anonymous

не меняет наблюдаемого поведения

Я, конечно, от жизни отстал, но как давно не выполняется это отношение: side-эффект == наблюдаемое поведение?

Deleted
()
Ответ на: комментарий от Deleted

как давно не выполняется это отношение: side-эффект == наблюдаемое поведение?

Не знаю, как давно. Думаю, как минимум со времён C89/C++98.

Стандарт определяет оба понятия: side-эффект и наблюдаемое поведение. И согласно этим определениям, side-эффект != наблюдаемое поведение. Корректная реализация должна сохранять только последнее.

anonymous
()
Ответ на: комментарий от anonymous

Тогда volatile никогда не влияет на модификацию. Но ты можешь убедиться в обратном, добавив этот квалификатор в тот код и сравнив выхлоп

Deleted
()
Ответ на: комментарий от Deleted

Не буду столь категоричным, многие тонкости сделаны, всё таки, по уму(внимание на правило вывода из prvalue).

Обожаю эти ответы на куски. А прочитать то, что там написано далее, не?

Если не рассматривать void как тип, в правилах появится исключение.

Это кресты. Ога, и теряется весь смысл и вся логика. На самом деле тут исключения нет, всё это описывается и без шизофрении над void.

Можно не вернуть ничего, а именно return; Таким образом return void; == return;. Это полностью логично и ложится на всю логику.

Здесь не согласен. Оба выражения: i и *ip представляют собой обращение к одной и той же ячейке памяти

У тебя явные проблемы с логикой. Если i и *ip указывают на одну «ячейку»( опять же, колхозное понимание - ни на какую ячейку ничего не указывает), то каким образом из этого следует то, что * ip является указателем на i?

Если проще. Вася и Петя являются ссылкой на мамку, ведь они братья. Следует ли из этого то, что Вася является ссылкой на петю? Нет.

Переменная есть - есть объект, который находится в рамках какой-то памяти. Будь то внутренняя память структуры, либо «функции», либо «программы». Указатель является ссылкой на эту память. И только на неё. К самое переменной он никакого отношения не имеет.

Простой пример struct { int i;} a; - на что указывает адрес a/i? Ни на что - он не имеет никакого отношения ни к i, ни к a.

Давай попроще. У тебя есть пространство. Ты поставил туда сортир. Является ли ссылка на какую-то часть пространства ссылкой на сортир? Нет. Сортир лишь находится в этом пространстве и не более того.

vcerloman
()
Ответ на: комментарий от anonymous

Что значит «тогда»?

Если рассуждать согласно твоей модели: side-эффект != наблюдаемое поведение

Почему не влияет?

Та же цитата из стандарта сообщает: модификация - side-эффект, обращение(у нас в примере только запись) к volatile - side-эффект. Что так, что так. Но фактический результат отличается

Deleted
()
Ответ на: комментарий от Deleted

Если рассуждать согласно твоей модели

Переход на личности засчитан.

Это не «моя модель». Это определения стандарта. Можешь сам посмотреть, драфты доступные бесплатно.

Та же цитата из стандарта сообщает: модификация - side-эффект, обращение(у нас в примере только запись) к volatile - side-эффект. Что так, что так. Но фактический результат отличается

В стандарте сказано, что реализация не должна менять наблюдаемого поведения, а не что она не должна выкидывать сайд-эффект.

Запись в объект (через не-volatile lvalue) это site effect, но не наблюдаемое поведение. А доступ к объекту посредством volatile glvalues это наблюдаемое поведение.

Это так сложно доходит?

anonymous
()
Ответ на: комментарий от Deleted

Ничего не понял. Где именно в этой теме спуск на «физический уровень», почему вдруг он не обоснованный и с чего он вдруг стал фейлом?

По ссылке скорее проблема в том, что авторы шланга идиоты, которые не осилил понять концепцию UB, как и подавляющие большинство колхозников, которые реальность дала подарок - они стали программистами, а не пошли мыть полы. Меня всегда удивляли подобные люди. Зачем, будучи деревом, пытаться о чём-то рассуждать и кого-то обвинять?

Где в стандарте запрещёны UB? Нигде. С чего вдруг идиоты решили, что они запрещены? У экспертов всегда было плохо с логикой. Они не понимают, что если бы UB == запретить, то так в стандарте бы и писалось. Зачем вводить новое понятие?

Но подобное находится выше уровня их понимания.

vcerloman
()
Ответ на: комментарий от vcerloman

прочитать то, что там написано далее

Я привёл другой позитивный момент в противовес негативному - ты же понимаешь, что только указателями и разыменованием язык не ограничивается(даже pure c).

Если i и *ip указывают на одну «ячейку»( опять же, колхозное понимание - ни на какую ячейку ничего не указывает)

Обрати внимание - я не говорил «указывают». И уж совсем неясно, с чего ты взял вот это:

то каким образом из этого следует то, что * ip является указателем на i?

Если предположить, что * перед ip - опечатка и не нужна, ответ прост: ip хранит адрес i, это и есть отношение указания.

К самое переменной он никакого отношения не имеет

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

Переменная есть - есть объект, который находится в рамках какой-то памяти

указатель таки указывает на переменную)

Является ли ссылка на какую-то часть пространства ссылкой на сортир? Нет

Таки да, если эта часть пространства - и есть тот самый сортир :-)

Deleted
()
Ответ на: комментарий от anonymous

Переход на личности засчитан

Да ты же упорот!!! Какой переход на личности? Лол :-)

Это не «моя модель»

Я сейчас с тобой о ней разговариваю, ты мне её привёл. Гораздо удобнее ссылаться на неё именно таким образом. Что с тобой не так?

доступ к объекту посредством volatile glvalues это наблюдаемое поведение

Лучше цитату дай

Deleted
()
Ответ на: комментарий от vcerloman

Несколько человек упорно видели баг в clang-е там, где его нет.

не осилили понять концепцию UB

Обсуждалось уже(там и продолжение есть), ну да ладно.

Где в стандарте запрещёны UB?

Там речь была скорее о том, что UB наоборот слишком много

Deleted
()
Ответ на: комментарий от Deleted

Ну объясни мне тогда, почему компилятор выпиливает, например, такое:

Т.к. int x[10] дальше не используется, то компилятор в праве выпилить эту часть кода.

Как вправе выпилить цикл тут:

#include <cstddef>

void bar(int* x, size_t count);

void foo()
{
    int x[10];
    bar(x, sizeof(x)/sizeof(x[0]));

    for (auto& i:x) i=0;
}

andreyu ★★★★★
()
Ответ на: комментарий от anonymous

Тоже не переход на личности?

Разупорин внутривенно :-)

ссылка

Ага, вижу. Видимо, у меня теминология страдает. За ссылку спасибо(тебе. oh, shi~ опять на личности перешёл)

Deleted
()
Ответ на: комментарий от Deleted

Ага, вижу. Видимо, у меня теминология страдает.

Я думаю, можно сказать так: наблюдаемое поведение — это то, что видно «снаружи» C++-программы, а сайд-эффекты — что видно «внутри» C++-программы: для её потоков выполнения.

anonymous
()
Ответ на: комментарий от anonymous

Я просто под side-эффектом в зависимости от контекста разные вещи подразумевал

Deleted
()
Ответ на: комментарий от Deleted

Как же сложно с вами, деревьями, говорить. Это ведь полная неахинея и неадекват.

Я привёл другой позитивный момент в противовес негативному -

Врёшь. Ты не привёл, а попытался оспорить моё утверждение, выдернув из него кусок.

ты же понимаешь, что только указателями и разыменованием язык не ограничивается(даже pure c).

К чему ты написал эту ахинею и что из неё следует? Я где-то говорил о том, что язык ограничивается «только указателями и разыменованием»? Нет.

Обрати внимание - я не говорил «указывают». И уж совсем неясно, с чего ты взял вот это:

Перед тем как нести ахинею - соотноси свои возможности с реальность, а иначе ты обделаешься в первую же секунду. Что ты и сделал:

указатель таки указывает на переменную)

Если предположить, что * перед ip - опечатка и не нужна, ответ прост: ip хранит адрес i, это и есть отношение указания.

Неверно. Адрес не имеет никакого отношения к i - примеры тебе уже дали. Ты их заигнорил.

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

Я тебе уже сказал - твои колхозные рассуждения о ячейках памяти - есть ахиеня, полностью невменяемая. Это первое.

Второе, абсолютно неважно кто и к чему имеет отношения, я тебе уже сказал. Если А имеет отношение к С и есть Б имеет отношение С, то из этого никак не следует то, что А имеет отношение к Б.

указатель таки указывает на переменную)

В твоих больных фантазиях.

Таки да, если эта часть пространства - и есть тот самый сортир :-)

Я тебе уже сказал - знай своё место и не пытайся со мною играть в эти игры. Ты можешь очень быстро обделаться.

Хорошо, если ты начал нести ахинею. Указатель у нас является адресом, а любая область имеет начало и конец. Именно поэтому, имея только начало - мы не можем определить область. Указатель же имеет начало и конец, но. Т.к. ты табуретка, которая несёт рандомную ахинею - ты уже обделался, а именно:

опечатка и не нужна, ответ прост: ip хранит адрес i, это и есть отношение указания.

Ты определил указатель как адрес, а значит только как начало. Таким образом - начальная точка включает в себя бесчисленное множество участков пространства.

И тут ты попал. Если ты ограничишь область - ты помножишь сам себя на ноль, а если не ограничишь - ты никак не можешь ссылаться на конкретный объект.

И нет, вася, это не будет тем самым сортиром. Сортир там может быть, а может не быть. Это первое.

Второе - сортир является значением, а не переменной. Название и владелец сортира у нас куда-то потерялся.

vcerloman
()
Ответ на: комментарий от Deleted

Несколько человек упорно видели баг в clang-е там, где его нет.

Он там есть. Да и ты не ответил на вопрос.

Там речь была скорее о том, что UB наоборот слишком много

Я тебя не спрашивал про много, либо мало. Я вижу идиотов, которые не осилил понять, что такое UB. Эти идиоты пользуются тем, что понятие предполагает свободную трактовку поведения, и идиоты это трактуют как «нельзя» и именно в этом проблема.

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

И этот пример типичное тому доказательство. Идиоты решили трактовать UB как нельзя, и я тебе уже об этом сказал. Если поведение чего-то не определено, то из этого никак не следует то, что этого произойти не может, либо что получить это УБ нельзя.

vcerloman
()
Ответ на: комментарий от vcerloman

Если i и *ip указывают на одну «ячейку»( опять же, колхозное понимание - ни на какую ячейку ничего не указывает), то каким образом из этого следует то, что * ip является указателем на i?

Тебя смутило слово «points» в комментарии? Немного неудачно выбрано, да. Но оно тут не означает, что выражение *ip это указатель. Оно используется как синоним к determines (ср. с http://eel.is/c draft/basic.lval#1.1: A glvalue is an expression whose evaluation determines the identity of an object, bit-field, or function.). Когда в стандарте говорится про glvalue-выражения и объекты, которые они обозначают, используют несколько синонимов: «determines», «designates», «references» (это не значит, что выражение — это ссылка, у выражений вообще ссылочного типа не бывает) и вот ещё «points».

В комментарии просто сказано, что выражение *ip обозначает тот же объект, что обозначало бы выражение i.

Предвидя вопрос «А прочитать то, что там написано далее, не?»: что дальше написано — прочитал. Какая-то шизанутая гуманитарщина.

anonymous
()
Ответ на: комментарий от vcerloman

неахинея и неадекват

Без комментариев

попытался оспорить моё утверждение

Не, это так не работает. Пруфы на попытку оспорить давай.

Адрес i не имеет никакого отношения к i

ОМГ

примеры тебе уже дали

ссылку, а лучше - цитату

абсолютно неважно кто и к чему имеет отношения
Если А имеет отношение к С и есть Б имеет отношение С, то из этого никак не следует то, что А имеет отношение к Б

o_O

Указатель у нас является адресом

No sir! Указатель является переменной, содержащей адрес

имея только начало - мы не можем определить область

В том числе из-за этого разыменовывать void* запрещено. А так для этого есть тип(вполне определённого размера)

И тут ты попал

Не, не, не. Попал здесь только один балабол, анскильная лалка и, судя по этому:

И нет, вася, это не будет тем самым сортиром. Сортир там может быть, а может не быть. Это первое.
Второе - сортир является значением, а не переменной. Название и владелец сортира у нас куда-то потерялся.

специалист-ассенизатор, не умеющий в контекст

Deleted
()
Ответ на: комментарий от vcerloman

обделаться

проверить штанишки

сортир

Слушай, я тут подумал, а не является ли вот это

специалист-ассенизатор

твоим основным занятием?

Deleted
()
Ответ на: комментарий от anonymous

Тебя смутило слово «points» в комментарии? Немного неудачно выбрано, да. Но оно тут не означает, что выражение *ip это указатель.

Выражение *ip тут непричём. Я там чётка указал причину по которой это является ахинеей, а именно ip никаким образом не имеет НИКАКОГО отношения к i. i является объектом в памяти, которая совершенно не имеет отношения к i. Указатель - это про память, которая находится снизу от i, именно поэтому он никаким образом не может быть указателем на i - он существует совершенно на другом уровне.

В комментарии просто сказано, что выражение *ip обозначает тот же объект, что обозначало бы выражение i.

Ахинея там сказана. Указатель на i предполагает ДОСТУП через i, что рушит на ноль всю логику, которая описана в данном примере. Логика предполагает доступ к значению не через i, именно по этому *ip имеет совершенно иные и не зависящие от i квалификаторы доступа.

vcerloman
()
Ответ на: комментарий от vcerloman

i является объектом в памяти, которая совершенно не имеет отношения к i

Указатель - это про память, которая находится снизу от i, именно поэтому он никаким образом не может быть указателем на i - он существует совершенно на другом уровне

Мне первое, конечно, больше понравилось :-)

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.