我想知道这样做是否安全?
wchar_t wide = /* something */;
assert(wide >= 0 && wide < 256 &&);
char myChar = static_cast<char>(wide);
如果我相当确信宽字符将落在ASCII范围内。
我想知道这样做是否安全?
wchar_t wide = /* something */;
assert(wide >= 0 && wide < 256 &&);
char myChar = static_cast<char>(wide);
如果我相当确信宽字符将落在ASCII范围内。
为什么不直接使用库例程wcstombs
呢。
wctomb()
函数:它在ANSI标准中,所以您可以信任它。即使wchar_t
使用的代码超过255,它也能正常工作。但是您几乎肯定不想使用它。
wchar_t
确实是一个整数类型,因此如果您真的这样做,编译器不会报错:char x = (char)wc;
但是因为这是一个整型,所以绝对没有理由这样做。如果你不小心阅读了Herbert Schildt的C: The Complete Reference或基于此的任何 C 书籍,则你已经完全错误地受到了误导。字符应该是int
或更好的类型。这意味着你应该这样写:
int x = getchar();
而不是这个:
char x = getchar(); /* <- WRONG! */
在整型方面,char
是毫无价值的。你不应该编写以 char
类型作为参数的函数,也不应该创建临时变量来存储 char
类型,同样的建议也适用于 wchar_t
。
char*
可能是字符串的一个方便的 typedef,但将其视为“字符数组”或“指向字符数组的指针”是一个初学者的错误想法——尽管 cdecl 工具说了什么。像这样将其视为实际的字符数组:
for(int i = 0; s[i]; ++i) {
wchar_t wc = s[i];
char c = doit(wc);
out[i] = c;
}
这个方法是完全错误的。它不会做你想要的事情;它会以微妙且严重的方式中断,在不同平台上表现不同,而且你肯定会让用户感到非常困惑。如果你看到这条信息,那么你正在尝试重新实现已经包含在 ANSI C 中的 wctombs()
,但这仍然是错误的。
你真正需要的是 iconv()
,它可以将一个字符编码从一种编码方式(即使它被打包成 wchar_t
数组)转换为另一种编码方式的字符编码。
现在去读一下这篇文章,来了解 iconv 的问题所在。
cin.getline()
对char[]
进行操作。 - Mike Cchar
是毫无价值的"这个说法是一个非常有争议的陈述。 - daniusassert
是在调试模式下确保某些内容为真,而在发布版本中不会有任何影响的。最好使用if
语句并为超出范围的字符制定一个替代计划,除非唯一出现超出范围的字符的方式是通过程序错误。
此外,根据您的字符编码,您可能会发现Unicode字符0x80到0xff及其char
版本之间存在差异。
一种简单的方法是:
wstring your_wchar_in_ws(<your wchar>);
string your_wchar_in_str(your_wchar_in_ws.begin(), your_wchar_in_ws.end());
char* your_wchar_in_char = your_wchar_in_str.c_str();
我已经使用这种方法多年了 :)
我之前写了一个简短的函数,用于将wchar_t数组打包成char数组。不在ANSI代码页(0-127)中的字符将被替换为“?”字符,并且它可以正确处理代理对。
size_t to_narrow(const wchar_t * src, char * dest, size_t dest_len){
size_t i;
wchar_t code;
i = 0;
while (src[i] != '\0' && i < (dest_len - 1)){
code = src[i];
if (code < 128)
dest[i] = char(code);
else{
dest[i] = '?';
if (code >= 0xD800 && code <= 0xD8FF)
// lead surrogate, skip the next code unit, which is the trail
i++;
}
i++;
}
dest[i] = '\0';
return i - 1;
}
w
应该是什么?难道不应该是 src
吗? - Olorinchar* wchar_to_char(const wchar_t* pwchar)
{
// get the number of characters in the string.
int currentCharIndex = 0;
char currentChar = pwchar[currentCharIndex];
while (currentChar != '\0')
{
currentCharIndex++;
currentChar = pwchar[currentCharIndex];
}
const int charCount = currentCharIndex + 1;
// allocate a new block of memory size char (1 byte) instead of wide char (2 bytes)
char* filePathC = (char*)malloc(sizeof(char) * charCount);
for (int i = 0; i < charCount; i++)
{
// convert to char (1 byte)
char character = pwchar[i];
*filePathC = character;
filePathC += sizeof(char);
}
filePathC += '\0';
filePathC -= (sizeof(char) * charCount);
return filePathC;
}
char
'的范围可以与'signed char
'或'unsigned char
'中的任何一个相同。对于无符号字符,您的范围是正确的;理论上,对于有符号字符,您的条件是错误的。实际上,很少有编译器会反对 - 结果将是相同的。assert
中的最后一个&&
是语法错误。char
、signed char
和 unsigned char
三种类型合称为字符类型。实现必须将 char
定义为与 signed char
或 unsigned char
具有相同的范围、表示和行为。 脚注 45 表示: <limits.h>
中定义的 CHAR_MIN
将具有值 0 或 SCHAR_MIN
中的一个,这可以用来区分两个选项。无论选择哪个选项,char
都是另一种类型,与其他两种类型不兼容。 - Jonathan Lefflerchar
对象可以取与 signed char
或 unsigned char
相同的值;具体使用哪一个是由实现定义的。我认为在 C++14 标准中没有任何实质性变化。最终结果与 C 标准引用相同——普通的 char
与 unsigned char
或 signed char
相同,并且由实现决定使用哪个。 - Jonathan Leffler也可以将 wchar_t 转换为 wstring --> string --> char
wchar_t wide;
wstring wstrValue;
wstrValue[0] = wide
string strValue;
strValue.assign(wstrValue.begin(), wstrValue.end()); // convert wstring to string
char char_value = strValue[0];
wstrValue
中的一个零字符(请参考第 wstrValue[0] = wide
行)。如果实现缓存它,则字符串的长度将不正确,并且在稍后访问它时可能会导致访问冲突。 - AntonKint(wchar_t(255)) == int(char(255))
当然是成立的,但这只意味着它们具有相同的int值。它们可能不代表相同的字符。char(0xFF)
是与wchar_t(0x02D9)
(点上方)相同的字符,而不是wchar_t(0x00FF)
(带分音符的小y)。'A' != 65
。