开发者

Implementing mbsnrtowcs in terms of mbsrtowcs

开发者 https://www.devze.com 2023-04-06 18:49 出处:网络
In an almost complete effort to port libc++ to Windows, I need the function mbsnrtowcs, and thought that the easiest way would be to implement it in terms of mbsrtowcs:

In an almost complete effort to port libc++ to Windows, I need the function mbsnrtowcs, and thought that the easiest way would be to implement it in terms of mbsrtowcs:

size_t mbsnrtowcs( wchar_t *__restrict__ dst, const char **__restrict__ src,
               size_t nmc, size_t len, mbstate_t *__restrict__ ps )
{
    char* nmcsrc = new char[nmc+1];
    strncpy( nmcsrc, *src, nmc );
    nmcsrc[nmc] = '\0';
    const size_t result = mbsrtowcs( dst, &nmcsrc, len, ps );
    delete[] nmcsrc;
    return result;
}

The problem here is that mbsrtowcs needs &nmcsrc to be of type const char**, which is isn't, because it is a string I just copied the first nmc elements into, and appended a \0 character to. How can I work around this? Strictly speaking, this is compiled as C++, so perhaps a const_cast would do little harm here? I also have access to c++0X (libc++ is/requires a subset c++0x).

Edit: the Clang error message reads:

M:\Development\Source\libc++\src\support\win32\support.cpp:37:27: error: no matching function for call to 'mbsrtowcs'
const size_t result = mbsrtowcs( dst, &nmcsrc, len, ps );
                      ^~~~~~~~~
M:/Development/mingw64/bin/../lib/clang/3.0/../../../x86_64-w64-mingw32/include\wchar.h:732:18: note: candidate function not viable: no known conversion from 'char **' to 'const char **restrict' for 2nd argument;
  size_t __cdecl mbsrtowcs(wchar_t * __restrict__ _Dest,const char ** __restrict__ _PSrc,size_t _Count,mbstate_t * __restrict__ _State) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
                 ^

EDIT2: To fix what was wrong Re. Matthieu, I have changed my naive implementation like so:

size_t mbsnrtowcs( wchar_t *__restrict__ dst, const char **__restrict__ src,
                   size_t nmc, size_t len, mbstate_t *__restrict__ ps )
{
    char* local_src = new char[nmc+1];
    char* nmcsrc = local_src;
    strncpy( nmcsrc, *src, nmc );
    nmcsrc[nmc] = '\0';
    const size_t result = mbsrtowcs( dst, const_cast<const char **>(&nmcsrc), len, ps );
    // propagate erro开发者_如何转开发r
    if( nmcsrc == NULL )
        *src = NULL;
    delete[] local_src;
    return result;
}

And I have added a FIXME saying that the proper way to do this would be implementing it via mbrtowc.


There is an issue here (not really related to the const I think).

mbsrtowcs might set *src to NULL.

mbsnrtowcs is supposed to do the same, of course.

However for you here it causes a 2 bugs:

  • Because you created a local alias, if mbsrtowcs set *src to NULL it is not reflected for the caller of mbsnrtowcs
  • mbsnrtowcs has a memory leak if nmcsrc is set to NULL

Perhaps that simply biting the bullet and implementing mbsnrtowcs in terms of mbrtowc would be more efficient ?

If you need to implement both (as I guess you do), you could also reverse the problem on its head and implement mbsrtowcs in terms of mbsnrtowcs simply by calling strlen at the beginning without loss of generality (and avoid the copy).


There's no problem, since the function expects a more restrictive interface. So you can just cast the pointer:

const size_t result = std::mbsrtowcs(dst, const_cast<const char **>(&nmcsrc), len, ps);

I'm not sure about restrict; you may need to add that to the cast as well (not on GCC, though) - that's a compiler-dependent matter, though, as there is no restrict in C++.

0

精彩评论

暂无评论...
验证码 换一张
取 消