Как интерпретировать двоичные данные как целое число?

Кодовая база на работе содержит некоторый код, который примерно походит на это:

#define DATA_LENGTH 64

u_int32 SmartKey::SerialNumber()
{
    unsigned char data[DATA_LENGTH];
    // ... initialized data buffer
    return *(u_int32*)data;
}

Этот код работает правильно, но GCC дает соблюдающее предупреждение:

warning: dereferencing pointer ‘serialNumber’ does break strict-aliasing rules

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

Обновление
С благодарностью к ответу James McNellis я придумал следующую служебную функцию:

template<class T, class Data>
T BinaryCast(const Data & inData)
{
    T ret;
    std::copy(&inData[0], &inData[0] + sizeof(ret), reinterpret_cast<char*>(&ret));
    return ret;
}

u_int32 SmartKey::SerialNumber()
{
    unsigned char data[DATA_LENGTH];
    // ... initialized data buffer
    return BinaryCast<u_int32>(data);
}

Не стесняйтесь предлагать улучшения!

5
задан StackedCrooked 27 May 2010 в 17:09
поделиться

4 ответа

Предупреждение выдается потому, что вы нарушаете правило строгого алиасинга.

Один из способов сделать это правильно - скопировать байты из буфера data в объект u_int32 и вернуть этот объект:

unsigned char data[DATA_LENGTH];
// ... initialized data buffer

u_int32 i;
assert(sizeof (i) <= DATA_LENGTH);
std::copy(&data[0], &data[0] + sizeof (i), reinterpret_cast<char*>(&i));
return i;

Это решение работает, потому что в C++ разрешено обращаться к объектам любого типа как к массивам char.

(std::copy() находится в <алгоритме>)

11
ответ дан 13 December 2019 в 05:31
поделиться

Не уверен , но я думаю, вы можете это сделать:

return (u_int32)&data;
-1
ответ дан 13 December 2019 в 05:31
поделиться

В языках C и C++ переинтерпретация памяти, занятой объектом одного типа, как объекта другого типа является незаконной - это приводит к неопределенному поведению. Некоторые компиляторы используют это правило для агрессивной оптимизации, связанной с псевдонимами. Как следствие, ваш код может работать не так, как ожидалось, если вы выполните вышеупомянутую реинтерпретацию.

В C/C++ можно интерпретировать любой объект как массив char, но нельзя брать отдельный массив char и интерпретировать его как объект другого типа. Именно это и делает ваш код.

Помимо проблем с псевдонимом, вы должны помнить, что отдельный автоматический массив char не гарантированно будет выровнен должным образом, чтобы быть прочитанным как значение u_int32.

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

u_int32 SmartKey::SerialNumber()
{
    unsigned char data[DATA_LENGTH];
    u_int32 u;
    // ...
    memcpy(&u, data, sizeof u);
    return u;
}

Конечно, вы должны быть уверены, что эндианальность данных совпадает с эндианальностью объектов u_int32 на вашей платформе.

2
ответ дан 13 December 2019 в 05:31
поделиться

Я думаю, что проблема на самом деле где-то в вашем убранном коде для инициализации структуры data[]. Я не думаю, что это имеет отношение к вашему касту, который в порядке.

0
ответ дан 13 December 2019 в 05:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: