понедельник, 21 сентября 2009 г.

reinterpret_cast

Мне нравится, когда в книге, сначала приводится пример программы с комментарием типа: «Ну что, видали как круто? Подбирайте челюсть со стола и читайте дальше, как это работает». Обожаю если примеры маленькие, например:
long a = 2829155;
cout << reinterpret_cast< char* >(&a);
Выведется строка «c++». Не отдам руку на отсечение, что у всех она будет именно такой, это требует дополнительного исследования.
В первой строке записали четырехбайтовое число. Затем взяли адрес переменной и нагло наврали компилятору, что этот адрес совсем не указатель на long. Это указатель на char. Как компилятор интерпретирует указатель на char? Как строку.
Почему именно «с++»? 2829155 == 0x002B2B63. То есть число 2829155 хранится в виде последовательности байт: 0x63(==99), 0x2B(==43), 0x2B(==43), 0x0(==0). Если посмотреть таблицу символов, то убедимся, что 99 это символ «c», а 43 – «+». Байт с нулем интерпретируется как конец строки.
Совсем нетрудно написать программу обратного преобразования, из строки в число

Я не смогу толково объяснить все тонкости reinterpret_cast, для этого есть учебники. Однако, точно могу сказать, что он запросто превращает указатель одного типа в указатель другого. А это влечет совершенно другую интерпретацию байтов памяти, в чем можно убедиться выше. Об опасностях нетрудно догадаться. Если в примере взять число побольше, то 4-й байт уже не будет равен нулю. Значит, приведенная к char* строка будет продолжаться до первого нуля, но уже неизвестно где он будет.
С классами тоже интересно.
class A {
  public:
  int i;
};
void main(){
  int b = 1;
  cout << (*reinterpret_cast< A* >(&b)).i; /*1*/
}
Тут говорится, что по адресу &b вовсе не число, а переменная класса A. Нужно ли говорить насколько это все опасно.

3 комментария:

  1. Первый пример немного неправильный, не хватает типа, к которому приводим.
    long a = 2829155;
    cout << reinterpret_cast(&a);

    ОтветитьУдалить
  2. Да верно, спасибо! Парсер решил, что это тег :)

    ОтветитьУдалить
  3. Ой, а у меня в комментарии тоже удалил его ))))

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

Можно использовать теги <b>, <i>