2

我正在尝试创建一个简单的数据结构,可以轻松地在 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
    }
}
4

3 回答 3

2

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

我注意到的其他一些错误/样式问题:

  • obj->length保留为分配的长度,而不是更新以匹配(宽)字符的长度。这是你的意图吗?
  • 演员阵容const char *是无用的和糟糕的风格。

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

编辑 2:该代码恰好对我有用,因为malloc它返回了一个新鲜的零填充缓冲区。由于您传递obj->lengthtombstowcs作为写入目标的最大值数wchar_t,因此它将用完空间并且无法写入空终止符,除非在源字符串。将其更改为obj->length+1,它应该可以正常工作。

于 2010-10-06T02:11:33.557 回答
1

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

此外,strlen(str)您应该使用mbstowcs(0, src, 0) + 1. 您还应该将类型更改strconst 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);
于 2010-10-06T10:04:34.690 回答
0

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

以下是所要求的附加信息:

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

长度 = 6

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

(其中 x = 随机数据)

长度失败!

供参考 printf("wcslen = %d\n",(int)wcslen(obj->string)); 打印为 wcslen = 11

于 2010-10-06T02:30:41.613 回答