wcslen() возвращает неверный результат при использовании пакета прагмы

Я обнаружил, что wcslen () возвращает неверный результат на gcc (и исправляет на msvc), когда источником является массив wchar_t, член упакованной структуры. Я знаю, что в linux sizeof(wchar_t) == 4 и в Windows его 2, но до сих пор не могу понять, как упаковка влияет на функцию wcslen (). Если я изменю wchar_t / wcslen на char / strlen, он будет работать должным образом.

#include <cstdint>
#include <cwchar>
#include <cstring>

#pragma pack(push, 1)

struct A
{
    uint8_t c;
};

struct B
{
    A  a;
    wchar_t buf[9];
};

#pragma pack(pop)


int main()
{
    const wchar_t* s = L"05.00.06";
    B b{};
    memcpy(b.buf, s, wcslen(s) * sizeof(wchar_t));

    return wcslen(b.buf);
}

Почему этот код, скомпилированный с помощью gcc, возвращает 7? Он должен вернуть 8(как это делает msvc). Кстати, скопированные байты верны (b.buf[7] == '6').

1 ответ

Решение

Поведение этого кода не определено и непредсказуемо. Вы проходитеwcslen function недопустимый указатель, поскольку он не обязательно соответствует требованиям выравнивания для своего типа.

Вероятно, на вашей платформе требование выравнивания для wchar_t равно 2. Таким образом, указатель, на который вы перешли wcslenне действует. Вы не видите подобного поведения сstrlen потому что в этом случае требование выравнивания равно 1, что означает полное отсутствие требования.

Не работайте с упакованными конструкциями, если не знаете, что выполнили требования к выравниванию своей платформы. В противном случае результаты совершенно непредсказуемы. На многих платформах ваш код выйдет из строя.

Другие вопросы по тегам