uint和char转换为unicode字符代码

时间:2015-05-19 11:30:23

标签: c# .net unicode

有人可以准确解释这段代码发生了什么:

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]);

3 个答案:

答案 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. 实际上,RFC(2616)将US-ASCII指定为编码,可能意味着ISO-8859-1。然而,RFC并不是一个有约束力的标准(它更像是希望从混​​乱中做出秩序:D),而且那里有大量的HTTP / 1.0和HTTP / 1.1客户端(和服务器)。实际上并不尊重这一点。像.NET作者一样,我坚持使用7位ASCII(编码的每字节字符数,当然不是真正的 7位)。

答案 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