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