【问题标题】:Encoding used in cast from char to byte从 char 到 byte 的转换中使用的编码
【发布时间】:2012-05-22 19:13:06
【问题描述】:

看看下面的 C# 代码:

byte[] StringToBytesToBeHashed(string to_be_hashed) {
    byte[] to_be_hashed_byte_array = new byte[to_be_hashed.Length];
    int i = 0;
    foreach (char cur_char in to_be_hashed)
    {
        to_be_hashed_byte_array[i++] = (byte)cur_char;
    }
    return to_be_hashed_byte_array;
}

(以上函数摘自these lines of code from the WMSAuth github repo

我的问题是:从字节到字符的转换在编码方面有什么作用?

我想它在编码方面确实没有做任何事情,但这是否意味着 Encoding.Default 是使用的那个,因此返回的字节将取决于框架如何编码特定 Operative 中的底层字符串系统?

此外,char 实际上是否大于一个字节(我猜是 2 个字节)并且实际上会省略第一个字节?

我正在考虑用以下方式替换所有这些:

Encoding.UTF8.GetBytes(stringToBeHashed)

你怎么看?

【问题讨论】:

    标签: c# character-encoding casting


    【解决方案1】:

    .NET Framework 使用 Unicode 来表示它的所有字符和字符串。 char 的整数值(可以通过转换为int 获得)等价于其 UTF-16 代码单元。对于基本多语言平面中的字符(构成您将遇到的大多数字符),此值是 Unicode 代码点。

    .NET Framework 使用Char 结构来表示Unicode 字符。 Unicode 标准用一个称为代码点的唯一 21 位标量数字标识每个 Unicode 字符,并定义了 UTF-16 编码形式,该形式指定代码点如何编码为一个或多个 16 位值的序列。每个 16 位值的范围从十六进制 0x00000xFFFF,并存储在 Char 结构中。 Char 对象的值是它的 16 位数字(序数)值。 — Char Structure

    char 转换为byte 将导致值大于255 的任何字符的数据丢失。尝试运行以下简单示例以了解原因:

    char c1 = 'D';        // code point 68
    byte b1 = (byte)c1;   // b1 is 68
    
    char c2 = 'ń';        // code point 324
    byte b2 = (byte)c2;   // b2 is 68 too!
                          // 324 % 256 == 68
    

    是的,您绝对应该改用Encoding.UTF8.GetBytes

    【讨论】:

      【解决方案2】:

      bytechar 之间的转换类似于使用 ISO-8859-1 编码(= Unicode 的前 256 个字符),除了在编码超过 U+00FF 的字符时它会默默地丢失信息。

      此外,char 实际上是否大于一个字节(我猜是 2 个字节)并且实际上会省略第一个字节?

      是的。 A C# char = UTF-16 代码单元 = 2 个字节。

      【讨论】:

        【解决方案3】:

        char 表示 16 位 UTF-16 代码点。将 char 转换为 byte 会导致字符的低字节,但是 Douglasdan04 都是错误的,因为它总是会悄悄地丢弃高字节.如果高字节不为零,则结果取决于是否设置了编译器选项检查算术上溢/下溢

        using System;
        namespace CharTest
        {
            class Program
            {
                public static void Main(string[] args)
                {   ByteToCharTest( 's' );
                    ByteToCharTest( 'ы' );
        
                    Console.ReadLine();
                }
        
                static void ByteToCharTest( char c )
                {   const string MsgTemplate =
                        "Casting to byte character # {0}: {1}";
        
                    string msgRes;
                    byte   b;
        
                    msgRes = "Success";
                    try
                    {   b = ( byte )c;  }
                    catch( Exception e )
                    {   msgRes = e.Message;  }
        
                    Console.WriteLine(
                        String.Format( MsgTemplate, (Int16)c, msgRes ) );
                }
            }
        }
        

        带有溢出检查的输出:

        Casting to byte character # 115: Success
        Casting to byte character # 1099: Arithmetic operation resulted in an overflow.
        

        没有溢出检查的输出:

        Casting to byte character # 115: Success        
        Casting to byte character # 1099: Success
        

        【讨论】:

        • 也许在某些奇怪的环境中它确实会抛出,但我认为在大多数环境中这种情况不会抛出。我已经在本地“Microsoft (R) Visual C# Compiler version 4.6.1590.0”和 repl.it: repl.it/Irlw/1 中进行了测试。并且在两种情况下都返回成功(没有像您的输出显示的例外)。
        • @Mariano Desanze,我不知道 Mono,但是如果他们自己的参考源清楚地显示输入字符是 compared(第 725 行)到 @ 987654330@转换前,如果char的值不适合一个字节,会抛出异常?我的环境并不奇怪——它是普通的 .NET 3.5 。静默丢弃高字节是个坏主意
        • 知道了:我在 SharpDevelop 中打开了 检查算术上溢/下溢 选项。所以这个转换的结果是矛盾的,即取决于编译器的设置!
        • 在这种情况下,很抱歉投反对票。如果你编辑你的答案,我会恢复它,否则我不能(也许你可以澄清它不会在每个环境中抛出)。但这真的很奇怪,因为即使在 microsoft.com/net 的在线解释器上,您也可以输入 char c = 'ы'; Console.WriteLine((byte)c); 并看到它返回“75”而不是异常。
        • 我已经编辑了答案——感谢您的反馈。看起来溢出检查默认是关闭的。
        猜你喜欢
        • 2014-12-11
        • 1970-01-01
        • 2015-09-06
        • 1970-01-01
        • 2011-07-22
        • 2013-01-27
        • 2013-04-28
        • 1970-01-01
        • 2011-04-22
        相关资源
        最近更新 更多