wcslen () возвращает неверный результат при использовании пакета прагмы - PullRequest
1 голос
/ 22 октября 2019

Я обнаружил, что wcslen () возвращает неверный результат для gcc (и правильный для msvc), когда source это массив 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 Ответ

4 голосов
/ 22 октября 2019

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

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

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

...