为啥 Guid.ToString("n") 与从相同 guid 的字节数组生成的十六进制字符串不同?

Posted

技术标签:

【中文标题】为啥 Guid.ToString("n") 与从相同 guid 的字节数组生成的十六进制字符串不同?【英文标题】:Why isn't Guid.ToString("n") the same as a hex string generated from a byte array of the same guid?为什么 Guid.ToString("n") 与从相同 guid 的字节数组生成的十六进制字符串不同? 【发布时间】:2011-03-20 05:29:23 【问题描述】:

考虑以下单元测试:

    [TestMethod]
    public void TestByteToString()
    
        var guid = new Guid("61772f3ae5de5f4a8577eb1003c5c054");
        var guidString = guid.ToString("n");
        var byteString = ToHexString(guid.ToByteArray());

        Assert.AreEqual(guidString, byteString);
    

    private String ToHexString(Byte[] bytes)
    
        var hex = new StringBuilder(bytes.Length * 2);
        foreach(var b in bytes)
        
            hex.AppendFormat("0:x2", b);
        
        return hex.ToString();
    

结果如下:

Assert.AreEqual failed. Expected:<61772f3ae5de5f4a8577eb1003c5c054>. Actual:<3a2f7761dee54a5f8577eb1003c5c054>.

【问题讨论】:

【参考方案1】:

嗯,它们是相同的,在前 4 个字节之后。前四个是相同的,只是顺序相反。

基本上,当从字符串创建时,它被假定为“big-endian”格式:左边的最高字节。但是,当在内部存储时(在 Intel 机器上),字节按“小端”排序:右边的最高字节。

【讨论】:

【参考方案2】:

如果比较结果,可以看到前三组是相反的:

61 77 2f 3a e5 de 5f 4a 8577eb1003c5c054 3a 2f 77 61 de e5 4a 5f 8577eb1003c5c054

那是因为在GUID structure中,这3个组被定义为DWORD和两个WORDs而不是字节:

0x00000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

所以在内存中,Intel 处理器以 Little-endian 顺序存储它们(最重要的字节在最后)。

【讨论】:

【参考方案3】:

GUID 的结构如下:

int a
short b
short c
byte[8] d

因此,对于a 表示的部分,您的代码会将字节反转。所有其他部分均已正确转换。

【讨论】:

为什么bc也不能颠倒过来? @SebastianGodelet - 因为他们是short 而不是int 我认为大于一个字节的所有内容都受字节序的影响:short s = 0xaf21; 可以存储:|af|21|或 |21|af| @SebastianGodelet - 可能,但字节序通常在 int 级别。 不是想变得讨厌,但我认为这里有一点误解...... 16 位整数,c.f. System.Int16 也受字节序的影响,例如: Unicode 传输编码:UTF-16LE 和 UTF-16BE,但仅限于:UTF-8,

以上是关于为啥 Guid.ToString("n") 与从相同 guid 的字节数组生成的十六进制字符串不同?的主要内容,如果未能解决你的问题,请参考以下文章

如果字符串为空,如何避免 Tostring 异常? [复制]

QT软件开发-得到唯一文件名-当前时间与GUID

为啥对于输出流,'\n' 优于 "\n"?

QT软件开发-得到唯一文件名-当前时间与GUID

QT软件开发-得到唯一文件名-当前时间与GUID

为啥要使用 strtok(line, "\n") **not** 来去除 fgets() 留下的换行符