有人可以准确解释这段代码发生了什么:
var letter= 'J';
char c = (char)(0x000000ff & (uint)letter);
我理解它正在获得角色的unicode表示,但我并不完全理解角色:
(0x000000ff & (uint)letter
0x000000ff的目的是什么,将字母转换为(uint),是否有一种实现相同结果的简便方法?
由于
好吧,看起来大多数人都认为这是一个不好的例子,我不想包括整个班级,但我想我也可以,所以你可以看到上下文。来自Reference Source's 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]);
答案 0 :(得分:2)
您正在解析HTTP标头,对吗?这意味着你不应该使用(任何)unicode编码。
HTTP标头必须是7位ASCII(与请求数据不同) 1 。这意味着您应该使用ASCII编码而不是默认编码。因此,在解析请求字节时,必须使用Encoding.ASCII.GetString
而不是Encoding.Default.GetString
。希望您没有使用StreamReader
- 由于很多原因,这可能是一个坏主意,包括标头与请求内容之间的(可能)编码不匹配。
修改强>
至于在微软源代码中的使用 - 是的,它发生了。不要试图复制那些类型的东西 - 它是一个黑客。请记住,你没有微软工程师拥有的测试套件和质量保证,所以即使它确实有效,你也最好不要复制这些黑客。
我认为它是以这种方式处理的,因为string
用于原则应该是&#34; ASCII字符串&#34;或只是byte[]
- 因为.NET只支持unicode字符串,这被视为较小的邪恶(事实上,这就是为什么代码明确检查string
没有&#39; t 包含任何unicode字符 - 它非常清楚标题必须是ASCII - 如果字符串包含任何非ASCII字符,它将显式失败。它是&#39; s在为其他人编写高性能框架时,通常需要进行权衡。
脚注:
答案 1 :(得分:1)
此代码的作用不是转换为Unicode。如果有的话,那就是另一种方式:
部分0x000000ff &
基本上丢弃了unicode字母的第二个字节,并将其转换为只有一个字节长的字母。或者更准确地说:它只保留最重要的字节并丢弃所有其他字节 - 这对于char
是相同的,因为它的大小为两个字节。
我仍然认为这没有任何意义,因为它会导致误报:实际使用两个字节的Unicode字母只会丢失其中一个字节,因此会变成另一个字母 <登记/>
我会简单地删除此代码,并在您使用name[i]
的任何地方使用c
。
答案 2 :(得分:1)
0x000000ff的目的是什么,将字母转换为(uint)
从[0..255]范围获取代码字符:char
在内存中占用2个字节
e.g:
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