Ral*_*ton 4 .net c# endianness
要将整数转换为十六进制格式的字符串,我正在使用 ToString("X4") ,如下所示:
int target = 250;
string hexString = target.ToString("X4");
Run Code Online (Sandbox Code Playgroud)
要从十六进制格式的字符串中获取整数值,我使用 Parse 方法:
int answer = int.Parse(data, System.Globalization.NumberStyles.HexNumber);
Run Code Online (Sandbox Code Playgroud)
但是,我与之交换数据的机器将字节按相反的顺序排列。
为了与示例数据保持一致,如果我想发送值 250,我需要一个字符串“FA00”(不是 00FA,这是 hexString 的含义)同样,如果我得到“FA00”,我需要将其转换为 250 而不是 64000。
如何设置这两种转换方法的字节序?
由于已被接受,Marc 的回答似乎已经解决了 OP 的原始问题。但是,从问题文本中我并不清楚为什么。这似乎仍然需要交换bytes,而不是像 Marc 的答案那样交换字节对。我不知道有任何合理的常见场景,其中一次交换 16 位有意义或有用。
对于规定的要求,恕我直言,写这个更有意义:
int target = 250; // 0x00FA
// swap the bytes of target
target = ((target << 8) | (target >> 8)) & 0xFFFF;
// target now is 0xFA00
string hexString = target.ToString("X4");
Run Code Online (Sandbox Code Playgroud)
请注意,以上假设我们实际上处理的是 16 位值,存储在 32 位int变量中。它将处理 16 位范围内的任何输入(注意需要屏蔽高 16 位,因为它们被<<运算符设置为非零值)。
如果交换 32 位值,则需要如下内容:
int target = 250; // 0x00FA
// swap the bytes of target
target = (int)((int)((target << 24) & 0xff000000) |
((target << 8) & 0xff0000) |
((target >> 8) & 0xff00) |
((target >> 24) & 0xff));
// target now is 0xFA000000
string hexString = target.ToString("X8");
Run Code Online (Sandbox Code Playgroud)
同样,需要屏蔽来隔离我们移动到特定位置的位。需要将<< 24结果转换回int与其他三个字节的 or-ing 之前,因为0xff000000是uint( UInt32) 文字并导致&表达式扩展为long( Int64)。否则,您将收到每个|运算符的编译器警告。
在任何情况下,由于这在网络场景中最常出现,因此值得注意的是 .NET 提供了可以帮助执行此操作的辅助方法:HostToNetworkOrder()和NetworkToHostOrder(). 在这种情况下,“网络顺序”始终是大端顺序,而“主机顺序”是托管当前进程的计算机上使用的任何字节顺序。
如果您知道您正在接收大端数据,并且您希望能够在您的过程中将其解释为正确的值,您可以调用NetworkToHostOrder(). 同样,如果您需要在需要 big-endian 的上下文中发送数据,您可以调用HostToNetworkOrder().
这些方法仅与三个基本整数类型工作:Int16,Int32,和Int64(在C#, ,short,int和long,分别地)。它们还返回传递给它们的相同类型,因此您必须小心符号扩展。问题中的原始示例可以这样解决:
int target = 250; // 0x00FA
// swap the bytes of target
target = IPAddress.HostToNetworkOrder((short)target) & 0xFFFF;
// target now is 0xFA00
string hexString = target.ToString("X4");
Run Code Online (Sandbox Code Playgroud)
同样,需要屏蔽,否则short该方法返回的值将被符号扩展为 32 位。如果0x8000在结果中设置了第15 位(即),则最终int值也将设置其最高 16 位。这可以通过为变量使用更合适的数据类型(例如,short当数据预期为有符号的 16 位值时)而无需屏蔽即可解决。
最后,我会注意到HostToNetworkOrder()和NetworkToHostOrder()方法,因为它们只是交换字节,所以它们是等价的。当机器架构为 little-endian †时,它们都交换字节。事实上,.NET 实现只是为了NetworkToHostOrder()调用HostToNetworkOrder(). 主要有两种方法使 .NET API 与原始 BSD 套接字 API 匹配,其中包括像htons()和这样的函数ntohs(),而该 API 又主要包括两个转换方向的函数,以便在代码中清楚一个人是否正在接收来自网络或向网络发送数据。
† 当机器架构是大端的时候什么都不做……它们作为通用的字节交换函数没有用处。相反,期望网络协议始终是大端的,并且这些函数用于确保交换数据字节以匹配任何机器架构。