将char转换为wchar_t的问题(长度错误)

时间:2010-10-06 02:01:01

标签: c unicode char wchar-t

我正在尝试创建一个简单的数据结构,这样可以轻松地在ASCII字符串和Unicode字符串之间来回转换。我的问题是函数mbstowcs返回的长度是正确的,但函数wcslen在新创建的wchar_t字符串上返回的长度不是。我在这里错过了什么吗?

typedef struct{

    wchar_t *string;
    long length; // I have also tried int, and size_t
} String;

void setCString(String *obj, char *str){

    obj->length = strlen(str);

    free(obj->string); // Free original string
    obj->string = (wchar_t *)malloc((obj->length + 1) * sizeof(wchar_t)); //Allocate space for new string to be copied to

    //memset(obj->string,'\0',(obj->length + 1)); NOTE: I tried this but it doesn't make any difference

    size_t length = 0;

    length = mbstowcs(obj->string, (const char *)str, obj->length);

    printf("Length = %d\n",(int)length); // Prints correct length
    printf("!C string %s converted to wchar string %ls\n",str,obj->string); //obj->string is of a wcslen size larger than Length above...

    if(length != wcslen(obj->string))
            printf("Length failure!\n");

    if(length == -1)
    {
        //Conversion failed, set string to NULL terminated character
        free(obj->string);
        obj->string = (wchar_t *)malloc(sizeof(wchar_t));
        obj->string = L'\0';
    }
    else
    {
        //Conversion worked! but wcslen (and printf("%ls)) show the string is actually larger than length
        //do stuff
    }
}

3 个答案:

答案 0 :(得分:2)

代码似乎对我很好。你能提供更多的上下文,例如你传递给它的字符串的内容,以及你正在使用的语言环境吗?

我注意到其他一些错误/风格问题:

  • obj->length保留为已分配的长度,而不是更新以匹配(宽)字符的长度。这是你的意图吗?
  • const char *的施法是无用且不好的风格。

编辑:经过讨论,您可能正在使用mbstowcs函数的不一致Windows版本。如果是这样,您的问题应该更新以反映。

编辑2:代码只适用于我,因为malloc返回了一个新的零填充缓冲区。由于您要将obj->length传递给mbstowcs作为写入目标的最大wchar_t值,因此它将耗尽空间并且无法写入空终止符,除非有源字符串中正确的多字节字符(一个需要多个字节)。将其更改为obj->length+1,它应该可以正常工作。

答案 1 :(得分:1)

您需要传递给mbstowcs() 的长度包括 L'\0'终结者字符,但您在obj->length()中的计算长度不包括它 - 您需要将1添加到传递给mbstowcs()的值。

此外,您应该使用strlen(str),而不是使用mbstowcs(0, src, 0) + 1来确定转换后的字符串的长度。您还应该将str的类型更改为const char *,并忽略演员阵容。可以使用realloc()代替free() / malloc()对。总的来说,它应该看起来像:

typedef struct {
    wchar_t *string;
    size_t length;
} String;

void setCString(String *obj, const char *str)
{
    obj->length = mbstowcs(0, src, 0);
    obj->string = realloc(obj->string, (obj->length + 1) * sizeof(wchar_t)); 

    size_t length = mbstowcs(obj->string, str, obj->length + 1);

    printf("Length = %zu\n", length);
    printf("!C string %s converted to wchar string %ls\n", str, obj->string);

    if (length != wcslen(obj->string))
            printf("Length failure!\n");

    if (length == (size_t)-1)
    {
        //Conversion failed, set string to NULL terminated character
        obj->string = realloc(obj->string, sizeof(wchar_t));
        obj->string = L'\0';
    }
    else
    {
        //Conversion worked!
        //do stuff
    }
}

Mark Benningfield指出mbstowcs(0, src, 0)是C标准的POSIX / XSI扩展 - 要获得仅在标准C下所需的长度,您必须使用:

    const char *src_copy = src;
    obj->length = mbstowcs(NULL, &src_copy, 0, NULL);

答案 2 :(得分:0)

我在Ubuntu linux上使用UTF-8作为语言环境运行。

以下是所要求的其他信息:

我使用完全分配的结构调用此函数并传入硬编码的“字符串”(不是L“字符串”)。所以我用本质上是setCString(* obj,“Hello!”)来调用函数。

长度= 6

!C string你好!转换为wchar字符串Hello!xxxxxxxxxxxxxxxxxxxx

(其中x =随机数据)

长度失败!

供参考 printf(“wcslen =%d \ n”,(int)wcslen(obj-> string));打印出来 wcslen = 11