unicode字符代码的int和char强制转换
本文关键字:char 转换 int 字符 代码 unicode | 更新日期: 2023-09-27 17:49:58
谁能解释一下这段代码到底是怎么回事?
var letter= 'J';
char c = (char)(0x000000ff & (uint)letter);
我理解它正在获得字符的unicode表示,但是我不完全理解:
的作用(0x000000ff & (uint)letter
0x000000ff和将字母转换为(uint)的目的是什么?是否有一种简便的方法可以实现相同的结果?
感谢更新好,看起来大多数人认为这是一个不好的例子,我不想包括整个类,但我想我可能会让你看到的背景。来自参考源的WebHeaderCollection:
private static string CheckBadChars(string name, bool isHeaderValue)
{
if (name == null || name.Length == 0)
{
// emtpy name is invlaid
if (!isHeaderValue)
{
throw name == null ?
new ArgumentNullException("name") :
new ArgumentException(SR.GetString(SR.WebHeaderEmptyStringCall, "name"), "name");
}
// empty value is OK
return string.Empty;
}
if (isHeaderValue)
{
// VALUE check
// Trim spaces from both ends
name = name.Trim(HttpTrimCharacters);
// First, check for correctly formed multi-line value
// Second, check for absenece of CTL characters
int crlf = 0;
for (int i = 0; i < name.Length; ++i)
{
char c = (char)(0x000000ff & (uint)name[i]);
switch (crlf)
{
case 0:
if (c == ''r')
{
crlf = 1;
}
else if (c == ''n')
{
// Technically this is bad HTTP. But it would be a breaking change to throw here.
// Is there an exploit?
crlf = 2;
}
else if (c == 127 || (c < ' ' && c != ''t'))
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidControlChars), "value");
}
break;
case 1:
if (c == ''n')
{
crlf = 2;
break;
}
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidCRLFChars), "value");
case 2:
if (c == ' ' || c == ''t')
{
crlf = 0;
break;
}
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidCRLFChars), "value");
}
}
if (crlf != 0)
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidCRLFChars), "value");
}
}
else
{
// NAME check
// First, check for absence of separators and spaces
if (name.IndexOfAny(InvalidParamChars) != -1)
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidHeaderChars), "name");
}
// Second, check for non CTL ASCII-7 characters (32-126)
if (ContainsNonAsciiChars(name))
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidNonAsciiChars), "name");
}
}
return name;
}
感兴趣的位是:
char c = (char)(0x000000ff & (uint)name[i]);
您正在解析HTTP标头,对吗?这意味着不应该使用(任何)unicode编码。
HTTP报头必须是7位ASCII(不像请求数据)1。这意味着您应该使用ASCII编码而不是默认编码。因此,在解析请求字节时,必须使用Encoding.ASCII.GetString
而不是Encoding.Default.GetString
。希望您没有使用StreamReader
-这将是一个坏主意,原因有很多,包括(可能)头和请求内容之间的编码不匹配。
至于在微软源代码中的使用-是的,它发生了。不要试图复制这些东西-它是一个hack。请记住,您没有微软工程师所拥有的测试套件和质量保证,所以即使它确实有效,您最好不要复制这样的hack。
我假设它是以这种方式处理的,因为使用string
为原则上应该是"ASCII字符串"或只是byte[]
-因为。net只支持unicode字符串,这被视为较小的邪恶(确实,这就是为什么代码显式检查string
不包含任何unicode字符-很清楚头必须是ASCII -如果字符串有任何非ASCII字符,它将显式失败。在为其他人编写高性能框架时,这只是通常的权衡。
脚注:
- 实际上,RFC(2616)指定US-ASCII作为编码,可能是指ISO-8859-1。然而,RFC并不是一个有约束力的标准(它更像是一种从混乱中整理秩序的希望:D),而且周围有很多HTTP/1.0和HTTP/1.1客户端(和服务器)实际上并不尊重这一点。像。net的作者一样,我坚持使用7位ASCII(当然是按每字节字符编码,而不是真正的 7位)。
0x000000ff和将字母转换为(uint)的目的是什么
从[0..][255] range: char
占用2字节内存
例如:
var letter= (char)4200; // ၩ
char c = (char)(0x000000ff & (uint)letter); // h
// or
// char c = (char)(0x00ff & (ushort)letter);
// ushort (2-byte unsigned integer) is enough: uint is 4-byte unsigned integer
这段代码所做的不是转换为Unicode。
部分0x000000ff &
基本上丢弃了unicode字母的第二个字节,并将其转换为只有一个字节长的字母。或者更准确地说:它只保留最有意义的字节,而丢弃其他所有字节——这对于char
来说是一样的,因为它的大小是两个字节。
我仍然认为这没有意义,因为它会导致误报:实际上使用两个字节的Unicode字母只会丢失其中一个字节,因此变成一个不同的字母
我会简单地去掉这些代码,在使用c
的地方使用name[i]
。