Re[6]: Массив и указатель: преобразование
От: Tscheineg  
Дата: 17.09.10 09:14
Оценка:
Блин, анонимно можно только начать тему, продолжать ее нельзя.

Задача такая. Есть функция Read(), которая читает последовательность байтов и возвращает осмысленную структуру TData.
int MakeInt(char ch0, char ch1, char ch2, char ch3);

struct TData {
  int  dw;
  char b;
  char b1;
};

// Распознает 5-и байтный буфер
TData Parse(const char* Buf)
{
  TData d;
  d.dw=MakeInt(Buf[0], Buf[1], Buf[2], Buf[3]);
  d.b =Buf[4];
  d.b1=Buf[5]; // #1
  return d;
}

TData Read(const char* Msg, int nSize)
{
  if (!Msg)           throw "Zero pointer";
  if (nSize<bBufSize) throw "Small buffer";
  return Parse(Msg);
}

В этом примере функция Parse() содержит ошибку в строке #1-выход за границу буфера. Компилятор ее, естественно, не обнаруживает, так как он понятия не имеет, какой длины у нас Buf. Для того, чтобы застраховаться от подобных ошибок, я хотел сделать так:
enum {
  bBufSize=5
};

typedef char TBufArr[bBufSize];

TData Parse(const TBufArr &Buf)
{ // Тело функции без изменений
  TData d;
  d.dw=MakeInt(Buf[0], Buf[1], Buf[2], Buf[3]);
  d.b =Buf[4];
  d.b1=Buf[5]; // #1
  return d;
}

TData Read(const char* Msg, int nSize)
{
  if (!Msg)           throw "Zero pointer";
  if (nSize<bBufSize) throw "Small buffer";
  const TBufArr &BufArr=reinterpret_cast<const TBufArr&>(Msg); // #2
  return Parse(BufArr);
}

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

Меня удивило то, что потребовался reinterpret_cast. Я думал, static_cast-а будет достаточно. По аналогии с наследованием классов: в одну сторону преобразование всегда возможно и, поэтому, выполняется автоматически, а в обратную сторону преобразование возможно, но не всегда, поэтому требуется разрешение программиста: static_cast (но не reinterpret_cast!).

Но меня ждал еще один сюрприз: MSVC все равно не сообщает об ошибке, так что вся эта затея обломилась. Как-то можно заставить компилятор замечать такие явные ошибки?

Еще обнаружил, что если строку #2 слегка изменить:
const TBufArr &BufArr=reinterpret_cast<const TBufArr&>(Msg+1);

то возникает ошибка error C2102: '&' requires l-value
В чем тут дело?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.