glibc wcslen() 是否期望数据沿 wchar_t 大小的边界对齐?

Does glibc wcslen() expect data alignment along wchar_t sized boundaries?

为了这个我已经绞尽脑汁好几个小时了。 glibc wcslen() 返回的值与给定输入字符串的预期值不同。我已经将问题缩小到可能的数据对齐问题,但即使那样对我来说也没有意义。我自己的转储字符串的函数似乎工作正常并且计算的大小类似于 wcslen() 应该如何工作。

    #ifndef WCHAR
        #define WCHAR wchar_t
    #endif

...

void DumpWCStr(const WCHAR *str)
{
    size_t len = 0, len2 = wcslen(str);

    while (*str != L'[=11=]')
    {
        printf("%lu %lc\n", (size_t)*str, *str);

        str++;
        len++;
    }

    printf("Size:  %lu (wcslen:  %lu)\n", len, len2);
}

void TestFunc()
{
    char *prebuffer = (char *)malloc(100 * sizeof(WCHAR) + 1);
    WCHAR *tempbuffer = (WCHAR *)(prebuffer + 1);
    WCHAR tempbuffer2[100];

    memset(prebuffer, 0xFF, 100 * sizeof(WCHAR) + 1);
    swprintf(tempbuffer, 100, L"%ls (%d)", L"test", 15);
DumpWCStr(tempbuffer);

    memset(prebuffer, 0xFF, 100 * sizeof(WCHAR) + 1);
    tempbuffer = (WCHAR *)prebuffer;
    swprintf(tempbuffer, 100, L"%ls (%d)", L"test", 15);
DumpWCStr(tempbuffer);

    memset(prebuffer, 0xFF, 100 * sizeof(WCHAR) + 1);
    swprintf(tempbuffer2, 100, L"%ls (%d)", L"test", 15);
DumpWCStr(tempbuffer2);
}

输出:

116 t
101 e
115 s
116 t
32
40 (
49 1
53 5
41 )
Size:  9 (wcslen:  8)
116 t
101 e
115 s
116 t
32
40 (
49 1
53 5
41 )
Size:  9 (wcslen:  9)
116 t
101 e
115 s
116 t
32
40 (
49 1
53 5
41 )
Size:  9 (wcslen:  9)

here 中的 glibc wcslen() 实现显示 wcslen() 实现为:

size_t
 __wcslen (const wchar_t *s)
 {
   size_t len = 0;
 
   while (s[len] != L'[=13=]')
     {
       if (s[++len] == L'[=13=]')
         return len;
       if (s[++len] == L'[=13=]')
         return len;
       if (s[++len] == L'[=13=]')
         return len;
       ++len;
     }
 
     return len;
  }

在第一个 swprintf() 之后尝试 printf("%ls\n", tempbuffer); 结果:

wcsrtombs.c:94: __wcsrtombs: Assertion `data.__outbuf[-1] == '[=14=]'' failed.

这可能是因为 __wcslen()__wcsrtombs() 中返回 8 而不是 9。

我正在将代码编译为 C++,目标是英特尔 x86/x64。

glibc wcslen() 是否期望数据在 wchar_t 大小的边界上对齐?这不是我阅读 wcslen() 源代码的方式,但它确实表现得像它期望数据对齐。

一般来说,C++ 总是要求对对象的所有访问至少与类型要求的边界对齐。这是因为对象不能存在于未对齐的地址中。因此,此要求并非特定于 wcslen.

在您的系统上,alignof(wchar_t) 可能大于 1,在这种情况下 prebuffer + 1 总是未对齐,因此不能包含 wchar_t 对象。

违反此要求会导致未定义的行为。