*** ВНИМАНИЕ: Блог переехал на другой адрес - demin.ws ***

воскресенье, 1 августа 2010 г.

volatile - это очень сильный модификатор в С++

Как-то по многим блогам эта тема недавно пробегала, но надо отдать должное, вопрос почему эта программа, будучи откомпилированной в Студии, печатает "1" вместо "0", озадачивает даже опытных программистов на С++ (или по крайней мере они дают неправильное объяснение причины происходящего).

#include <iostream>
volatile const char* p = "0";
int main() {
  std::cout << p << std::endl;
  return 0;
}

Для получение схожего эффекта в GCC надо заменить "0" на "false".

13 комментариев:

  1. В конце стоило все-таки объяснить, почему это работает именно так :)

    ОтветитьУдалить
  2. Потому что volatile const char* не приводится, согласно стандарту, к "просто" const char*, соответственно метод вывода в поток, определенный для "просто" const char* (прочитать строку по указателю) не применим. Ближайшее приведение, доступное компилятору - это приведение указателя к bool, что он и делает (и выводит значение true).

    ОтветитьУдалить
  3. Ну вообще-то тема действительно старая. Встречался с ней когда изучал перегруженные операторы. В STL не все необходимые операторы перегружены, операторы с аргументами:
    char*
    const char*
    volatile char*
    volatile const char*
    это все разные операторы и друг к другу они не приводятся просто так.

    ОтветитьУдалить
  4. я бы сказал, что «волатильная константа» — это, скорее, дыра в стандарте, нет?

    ОтветитьУдалить
  5. Не уверен что это следует понимать как дыру. Скорее переменную "volatile const" следует понимать как read-only переменную, которая тем не менее может измениться (например, железом).

    ОтветитьУдалить
  6. совершенно верно.
    но боюсь, если мы вынуждены догадываться, как следует понимать ту или иную конструкцию — это и есть лакуна в стандарте, увы.

    ОтветитьУдалить
  7. Например у нас есть контроллер датчика температуры. Датчик записывает значение температуры в память по DMA. Переменную, которая будет отображать этот кусок памяти, однозначно надо делать const (ибо можно в коде ошибку сделать), но она должна зачитываться при каждом обращении. Вот вам совершенно логичный пример "volatile const" без всяких дыр

    ОтветитьУдалить
  8. Ахтунг. При таком неявном преобразовании к bool хотелось бы видеть warning. В MSVC STL реализация оператора на консоль выводит 0 или 1. А в GCC - true или false. А вопрос и вправду каверзный ;)

    ОтветитьУдалить
  9. раз уж тут такие интересные вещи обсуждаются, объясните пожалуйста почему:

    &(*(ptrObj->ptrObj2)) - создается unnamed pointer на новый объект, поразрядную копию Obj2.
    а при:
    &(*ptrObj) - это тот же ptrObj pointer на все тот же Obj?

    Заранее благодарен за ответ.

    ОтветитьУдалить
  10. @kostiantyn: а можно более развернутый пример?

    ОтветитьУдалить
  11. @Александр: прошу прощения, сам себя перепутал и Вас попытался заодно с толку сбить. У меня в коде намного более сложный случай, объекты довольно таки комплексные. Вот я и не разобрался сразу. Только когда написал по Вашей просьбе более простой пример, аналог того, что у меня в коде происходит, он мне и показал, что операция &(*ptr) таки ничего не копирует в случае со сложными объектами. Будь то просто указатель или указатель внутри того, на что указывает указатель.
    (В теории вроде осуществляется копирование простого объекта интегрального типа из хипа в стек при применении операции разименовывания, но это явно не мой случай.)

    ОтветитьУдалить
  12. @kostiantyn: Факт. Всегда полезно попытаться объяснить проблему другому программисту, и часто в процессе объяснения наступает просветление для самого объясняющего, и проблема решается сама собой ;-). Удачи.

    ОтветитьУдалить
  13. Не обязательно даже "другому программисту". ;-) http://en.wikipedia.org/wiki/Rubber_duck_debugging

    ОтветитьУдалить