字节顺序 - 如何将c#整数转换为大端字节(无字节数组,只需一个字节)?

时间:2012-04-12 15:27:01

标签: c# java arrays byte endianness

当然我知道这与endianess有关。我知道Java是big-endian而C#是little-endian。

我有一个Java工作程序,它将字符串发送到外部系统。问题是他们需要在表示其长度的字符串的开始处使用2字节的标头。

在这个2字节的标题中,第一个是告诉字符串是否超过255个字符,如果不是,它总是0.但第二个字节(这是我在C#中无法正确的字节)将表示字符串的长度,如果第一个字节为0(几乎在所有情况下),它代表字符串的整个长度,假设为226。

所以在java中,我有这段代码来计算标题并附加原始字符串,这样我们就可以发送最终的字符串了,它运行得很好:

Java工作代码段:

String iso_str = iso_buf.toString();    // This contains original string without header

int iso_len = iso_str.length();     // We need to know if it exceeds 255

int i, j;
i = (int)(iso_len / 256);           // Always 0. It would be 1 if original string bigger than 255
j = (int)(iso_len % 256);           // Length of the string (most times 226)

Integer ii = new Integer(i);
Integer jj = new Integer(j);

byte[] bmsg_0200 = new byte[iso_len + 2];   // We create an array of bytes making room for the 2 bytes header and the original string
bmsg_0200[0] = ii.byteValue();      // Header byte number one
bmsg_0200[1] = jj.byteValue();      // Header byte number two

System.arraycopy(iso_str.getBytes(), 0, bmsg_0200, 2, iso_str.length()); // Then we just copy the original string in the array after the header         

String mensaje_str = new String(bmsg_0200); // Make the whole byte array into one string to send

在部分中说:bmsg_0200 [1] = jj.byteValue();是java实际上获取一个有效的字节值的地方(我认为当jj为226时它将-30放在那里)。并且最终系统理解这个标题,因此读取所有消息。

我尝试在.NET(C#)中复制代码,我有以下代码:

C#不工作的代码段:

int tramaISOLongitud = iso.Length;  // iso contains original string without header, We need to know if it exceeds 255

int i, j;
i = (int)(tramaISOLongitud / 256);  // Always 0. It would be 1 if original string bigger than 255
j = (int)(tramaISOLongitud % 256);  // Length of the string (most times 226)            

byte[] tramaISOBytes = new byte[tramaISOLongitud + 2];  // We create an array of bytes making room for the 2 bytes header and the original string
tramaISOBytes[0] = Convert.ToByte(i);   // Header byte number one
tramaISOBytes[1] = Convert.ToByte(j);   // Header byte number two

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud); // Then we just copy the original string in the array after the header

System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); 
string tramaISOHeader = enc.GetString(tramaISOBytes); // Make the whole byte array into one string to send

最后一个代码编译和所有内容,但在tramaISOBytes中获取错误的字节[1] = Convert.ToByte(j);因为是小端的。所以我尝试使用System.Net.IPAddress.HostToNetworkOrder,如下所示:

int tramaISOLongitud = iso.Length;  // iso contains original string without header, We need to know if it exceeds 255

int i, j;
i = (int)(tramaISOLongitud / 256);  // Always 0. It would be 1 if original string bigger than 255
j = (int)(tramaISOLongitud % 256);  // Length of the string (most times 226)    

int i2 = System.Net.IPAddress.HostToNetworkOrder(i);
int j2 = System.Net.IPAddress.HostToNetworkOrder(j);    

byte[] tramaISOBytes = new byte[tramaISOLongitud + 2];  // We create an array of bytes making room for the 2 bytes header and the original string
tramaISOBytes[0] = Convert.ToByte(i2);  // Header byte number one
tramaISOBytes[1] = Convert.ToByte(j2);  // Header byte number two

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud); // Then we just copy the original string in the array after the header

System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); 
string tramaISOHeader = enc.GetString(tramaISOBytes); // Make the whole byte array into one string to send

然后j2得到一个巨大的数字(如-503316480),它不能转换成单个字节因为太大而且我确实需要它在一个字节中,因为我说的标题只有2个字节长。有什么想法吗?

提前致谢。


好的我会以更简单的方式表达:

在C#中:

int test    = -10471344;
int test2   = -503316480;
int test3 = 57856;
byte b = (byte)test;
byte b2 = (byte)test2;
byte b3 = (byte)test3;

如果我们运行这些行,我们得到:     b = 80     b2 = 0     b3 = 0

那么,为什么数字-10471344转换为(字节)给出80;而其他人只给0?其实我对变量test2 = -503316480感兴趣我想把它转换成别的东西,然后我得到0.为什么b可以是80而其他的不能是0?


解决方案:正如Jim所说,我的问题与endianness没有任何关系(虽然我认为这是与此相关的一切),但关键知识是在.NET世界中将String转换为字节数组是没有问题,但是从字节数组回到字符串是你遇到问题的地方,因为你必须使用编码(ASCIIEncoding或UTF8Enconding),而且因为你的字节被破坏而出现问题。

在java中我没有遇到这种问题。

所以这是完成这项工作的代码块:

static byte[] addHeader2(string iso)
{
    int tramaISOLongitud = iso.Length;

    byte highByte = (byte)(tramaISOLongitud >> 8);
    byte lowByte = (byte)(tramaISOLongitud & 255);

    byte[] tramaISOBytes = new byte[tramaISOLongitud + 2];
    tramaISOBytes[0] = highByte;
    tramaISOBytes[1] = lowByte;

    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud);

    return tramaISOBytes;
}

我只是通过套接字发送该字节数组。

感谢所有人的帮助!

2 个答案:

答案 0 :(得分:2)

你的问题与endian-ness无关。当你进行算术运算时,系统是大端还是小印度并不重要。也就是说,鉴于此:

int len = 260;

byte highByte = (byte)(len >> 8);
byte lowByte = (byte)(len & 255);

Console.WriteLine("highByte = {0:X2}", highByte);
Console.WriteLine("lowByte = {0:X2}", lowByte);

highByte 始终为1,而lowByte 始终为4。

无需进行HostToNetWorkOrder转换。

现在,如果你正在使用负值,你的除法运算符和mod运算符会给你带来意想不到的结果。但你说它是一个2字节的长度值,你存储在一个int中,所以负值不应该给你一个问题。

我认为如果您单步执行原始C#代码,您将看到正确的值存储在tramaISOBytes数组的前两个位置。我怀疑当您尝试将生成的字节数组转换为字符串时会出现问题。您正在使用ASCIIEncoding将您的字节数组转换为字符串,这将破坏任何大于127(0x7Fh)的字节。

所以,而不是你的转换:

System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string tramaISOHeader = enc.GetString(tramaISOBytes);

您想使用8位编码。或许像ISO-8859-2这样的东西。基本上,你想要一些不会尝试进行任何转换的东西。或者,更好的是,如果你将它们放在一起进行传输,你甚至不应该转换回字符串。只是直接传输字节数组。这样就不会有事情被破坏了。

答案 1 :(得分:0)

将2个字节复制到一个字节数组中,尝试将字节转换为ushort:

bool remoteSystemIsLittleEndian = false;
byte[] stringLengthBytes = new byte[] { 1, 255 };

if (BitConverter.IsLittleEndian != remoteSystemIsLittleEndian)
{
    Array.Reverse(stringLengthBytes);
}

int stringLength = (int)BitConverter.ToUInt16(stringLengthBytes, 0);

这用于将数字转换回2字节数组:

bool remoteSystemIsLittleEndian = false;
int stringLength = 511;

byte[] stringLengthBytes = BitConverter.GetBytes((ushort)stringLength);

if (BitConverter.IsLittleEndian != remoteSystemIsLittleEndian)
{
    Array.Reverse(stringLengthBytes);
}