Подтвердить что ты не робот

Reinterpret_cast странность (выражение, разделенное запятыми)

При отладке некоторых наших кодов (С++) я нашел это:

inline std::string BufferToStr(
    const unsigned char* buffer,
    int index,
    size_t length)
{
   std::string retValue(reinterpret_cast<const char*>(&buffer[index], length));
   return retValue;
}

Проблема с этим кодом (с учетом отсутствия указателей и проверок длины строк) заключается в том, что закрывающая скобка reinterpret_cast была помещена после length, когда она должна была после &buffer[index]. Сначала я подумал, что это проблема с компилятором (используя VS2013), но после успешной компиляции с использованием VS2012 и gcc 4.6.3 я пришел к выводу, что это по какой-то причине разрешено. Код не будет работать ни в Windows, ни в Linux, поскольку в качестве указателя используется параметр длины.

Итак, мой вопрос - почему это компилируется? Глядя на документацию reinterpret_cast, я не могу найти там никакой документации, говорящей, что вы можете передать ей список значений, разделенных запятыми, и что он будет делать с ним.

4b9b3361

Ответ 1

reinterpret_cast принимает выражение . То, что у вас есть в скобках, есть выражение - "," operator с двумя подвыражениями, которое будет оцениваться с результатом последнего суб -expression.

Ответ 2

Это связано с запятой в c/С++. Код (выражение):

(&buffer[index], length)

эквивалентен (& buffer [index] не действует):

(length)

поэтому ваш код эквивалентен:

inline std::string BufferToStr(const unsigned char* buffer, int index, size_t length)
{
   std::string retValue(reinterpret_cast<const char*>(length));
   return retValue;
}

Ответ 3

Это оператор запятая. Он оценивает выражения с обеих сторон запятой, но возвращает результат правого выражения.

Причина, по которой компилятор не жалуется, заключается в том, что вы просто передаете компилятору, что результат выражения (типа size_t) должен рассматриваться как выражение const char*. То, что делает reinterpret_cast, позволяет лить почти любого типа почти любому типу, как бы он ни был глуп.

Ответ 4

reinterpret_cast < new_type > ( expression )        

reinterpret_cast принять выражение . Здесь у вас есть оператор запятой, который оценивает выражения с обеих сторон и возвращает выражение в виде выражения.

Фактически выражение (&buffer[index], length) здесь эквивалентно (length).

Просто посмотрите: http://msdn.microsoft.com/en-us/library/zs06xbxh.aspx или http://en.wikipedia.org/wiki/Comma_operator для объяснений операторов запятой.

В заключение, вы говорите своему компилятору, чтобы он передал size_t (результат выражения) в const char*, и он может это сделать.

Ответ 5

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

 warning: left operand of comma operator has no effect [-Wunused-value]
 std::string retValue(reinterpret_cast<const char*>(&buffer[index], length));
                                                                  ^

Вы можете увидеть живой пример.

Предупреждение сообщает нам, что мы используем оператор запятой, вначале это может быть немного озадачивающим, но reinterpret_cast не является вызовом функции в котором это не будет работать без использования скобок, поскольку мы можем видеть в этом надуманном примере, но выражение и в разделе 5.2 Постфиксные выражения черновик стандарта С++, грамматик для постфиксного выражения содержит:

postfix-expression:
   ...
   reinterpret_cast < type-id > ( expression )
   ...

и мы можем использовать expression в аргументе, поэтому comma operator отлично действует.