Предупреждение: приведение увеличивает необходимое выравнивание - PullRequest
8 голосов
/ 30 апреля 2010

Я недавно работаю над этой платформой, для которой унаследованная кодовая база выдает большое количество предупреждений «увеличение приведения требует выравнивания по N», где N - размер цели приведения.

struct Message
{
   int32_t id;
   int32_t type;
   int8_t  data[16];
};

int32_t GetMessageInt(const Message& m)
{
   return *reinterpret_cast<int32_t*>(&data[0]);
}

Надеюсь, очевидно, что "реальная" реализация была бы немного более сложной, но суть в том, что у меня откуда-то есть данные, я знаю , что они выровнены (потому что мне нужно id и type для выравнивания), и все же я получаю сообщение, что приведение увеличивает выравнивание, в примере, до 4.

Теперь я знаю, что могу подавить предупреждение с помощью аргумента для компилятора, и я знаю, что могу сначала преобразовать бит в скобках в void *, но на самом деле я не хочу проходить через каждый бит кода это требует такого рода манипуляций (их много, потому что мы загружаем много данных с диска, и эти данные поступают в виде буферов символов, чтобы мы могли легко перемещать указатели), но кто-нибудь может дать мне какие-то другие мысли по этой проблеме ? Я имею в виду, для меня это кажется таким важным и распространенным вариантом, что вы не захотите предупреждать, и если на самом деле есть возможность сделать это неправильно, то подавление предупреждения не поможет. Наконец, не может ли компилятор знать, как я, как на самом деле выровнен рассматриваемый объект в структуре, поэтому он не должен беспокоиться о выравнивании этого конкретного объекта, если только он не столкнулся с байтом или двумя?

1 Ответ

3 голосов
/ 30 апреля 2010

Одной из возможных альтернатив может быть:

int32_t GetMessageInt(const Message& m)
{
   int32_t value;
   memcpy(&value, &(data[0]), sizeof(int32_t));
   return value;
}

Для архитектуры x86 выравнивание не будет иметь большого значения, это скорее проблема производительности, которая на самом деле не имеет отношения к предоставленному вами коду. Для других архитектур (например, MIPS) неправильный доступ вызывает исключения CPU.


Хорошо, вот еще одна альтернатива:

struct Message
{
    int32_t id;
    int32_t type;
    union
    {
        int8_t  data[16];
        int32_t data_as_int32[16 * sizeof(int8_t) / sizeof(int32_t)];
        // Others as required
    };
};

int32_t GetMessageInt(const Message& m)
{
    return m.data_as_int32[0];
}

Вот вариант вышеупомянутого, который включает предложения от cpstubing06:

template <size_t N>
struct Message
{
    int32_t id;
    int32_t type;
    union
    {
        int8_t  data[N];
        int32_t data_as_int32[N * sizeof(int8_t) / sizeof(int32_t)];
        // Others as required
    };
    static_assert((N * sizeof(int8_t) % sizeof(int32_t)) == 0,
                  "N is not a multiple of sizeof(int32_t)");
};

int32_t GetMessageInt(const Message<16>& m)
{
    return m.data_as_int32[0];
}


// Runtime size checks
template <size_t N>
void CheckSize()
{
    assert(sizeof(Message<N>) == N * sizeof(int8_t) + 2 * sizeof(int32_t));
}

void CheckSizes()
{
    CheckSize<8>();
    CheckSize<16>();
    // Others as required
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...