上回书说到,如果用C语言来判断系统的字节存储顺序 Little endian 和 Big endian ,函数如下:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
union TestEndian_Unit
{
uint16_t value;
uint8_t bytes[2];
};
/*!
This function get endianness of current running environment.
Return value: 0 -- Little endian
1 -- Big endian
Exception 0xFF00 means error occurs.
Reference: http://en.wikipedia.org/wiki/Endianness
For example: x86, x86-64 and Windows on PowerPC use little endian;
FreeBSD on PowerPC and SPARC use big endian.
*/
int IsBigEndian()
{
union TestEndian_Unit flag;
flag.value = 0xFF00;
if(flag.bytes[0] == 0x00 && flag.bytes[1] == 0xFF)
{
return 0;
}
else if(flag.bytes[0] == 0xFF && flag.bytes[1] == 0x00)
{
return 1;
}
else
{
fprintf(stderr, "Error occurs in function IsBigEndian().\n");
exit(0xFF00);
}
}
那么,如何用托管代码来进行同样的判断呢?
方法一、借助Marshal
代码如下:
// -----------------------------------------------------------------------
// <copyright file="SystemInfo.cs" Author="Yaping Xin">
// Helper class to get system information.
// </copyright>
// -----------------------------------------------------------------------
namespace TestEndian
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Helper class to get system information.
/// </summary>
public class SystemInfo
{
/// <summary>
/// This function get endianness of current running environment.
/// Return value: False -- Little endian
/// True -- Big endian
/// Reference: http://en.wikipedia.org/wiki/Endianness
///
/// For example: x86, x86-64 and Windows on PowerPC use little endian;
/// FreeBSD on PowerPC and SPARC use big endian.
/// </summary>
/// <returns>True indicates big endian.</returns>
public static bool IsBigEndian()
{
const UInt16 value = 0xFF00;
byte[] bytes = ToBytes(value);
if (bytes[0] == 0x00 && bytes[1] == 0xFF)
{
return false;
}
else if (bytes[0] == 0xFF && bytes[1] == 0x00)
{
return true;
}
else
{
throw new ArithmeticException(
"Error occurs while judge system endian.");
}
}
/// <summary>
/// Convert UInt16 value to byte[2] array.
/// </summary>
/// <param name="value">the UInt16 value</param>
/// <returns>byte[2] array</returns>
private static byte[] ToBytes(UInt16 value)
{
IntPtr buffer = Marshal.AllocHGlobal(2);
try
{
Marshal.StructureToPtr(value, buffer, false);
byte[] bytes = new byte[2];
Marshal.Copy(buffer, bytes, 0, 2);
return bytes;
}
catch (Exception ex)
{
string message = string.Format(
"Error occurs while converting {0} to byte[2] array.",
value);
throw new Exception(message, ex.InnerException);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
}
}
方法二、用C#来模拟C的Union结构
文件列表:
- TestEndianUnit.cs
- SystemInfo.cs
TestEndianUnit.cs
// -----------------------------------------------------------------------
// <copyright file="TestEndianUnit.cs" Author="Yaping Xin">
// Union structure to test system Endianness.
// </copyright>
// -----------------------------------------------------------------------
namespace TestEndian
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Union structure to test system Endianness.
/// The C union structure definition is as below:
/// union TestEndian_Unit
/// {
/// uint16_t value;
/// uint8_t bytes[2];
/// };
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct TestEndianUnit
{
#region Data field
/// <summary>
/// Data field as TestEndian_Unit.value
/// </summary>
[FieldOffset(0)]
public UInt16 Value;
/// <summary>
/// Data field as TestEndian_Unit.bytes[0]
/// </summary>
[FieldOffset(0)]
public byte HByte;
/// <summary>
/// Data field as TestEndian_Unit.bytes[1]
/// </summary>
[FieldOffset(1)]
public byte LByte;
#endregion
#region Initialization
/// <summary>
/// Initializes a new instance of the TestEndianUnit struct.
/// </summary>
/// <param name="value">union struct value</param>
public TestEndianUnit(UInt16 value)
{
this.HByte = 0;
this.LByte = 0;
this.Value = value;
}
#endregion
}
}
SystemInfo.cs
// -----------------------------------------------------------------------
// <copyright file="SystemInfo.cs" Author="Yaping Xin">
// Helper class to get system information.
// </copyright>
// -----------------------------------------------------------------------
namespace TestEndian
{
using System;
/// <summary>
/// Helper class to get system information.
/// </summary>
public class SystemInfo
{
/// <summary>
/// This function get endianness of current running environment.
/// Return value: False -- Little endian
/// True -- Big endian
/// Reference: http://en.wikipedia.org/wiki/Endianness
///
/// For example: x86, x86-64 and Windows on PowerPC use little endian;
/// FreeBSD on PowerPC and SPARC use big endian.
/// </summary>
/// <returns>True indicates big endian.</returns>
public static bool IsBigEndian()
{
TestEndianUnit unit = new TestEndianUnit(0xFF00);
if (unit.HByte == 0x00 && unit.LByte == 0xFF)
{
return false;
}
else if (unit.HByte == 0xFF && unit.LByte == 0x00)
{
return true;
}
else
{
throw new ArithmeticException(
"Error occurs while judge system endian.");
}
}
}
}
方法三、用C#来模拟C的Union结构(unsafe)
文件列表:
- TestEndianUnit.cs
- SystemInfo.cs
TestEndianUnit.cs
// -----------------------------------------------------------------------
// <copyright file="TestEndianUnit.cs" Author="Yaping Xin">
// Union structure to test system Endianness.
// </copyright>
// -----------------------------------------------------------------------
namespace TestEndian
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Union structure to test system Endianness.
/// The C union structure definition is as below:
/// union TestEndian_Unit
/// {
/// uint16_t value;
/// uint8_t bytes[2];
/// };
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public unsafe struct TestEndianUnit
{
#region Data field
/// <summary>
/// Data field as TestEndian_Unit.value
/// </summary>
[FieldOffset(0)]
public UInt16 Value;
/// <summary>
/// Data field as TestEndian_Unit.bytes
/// </summary>
[FieldOffset(0)]
public fixed byte Bytes[2];
#endregion
#region Initialization
/// <summary>
/// Initializes a new instance of the TestEndianUnit struct.
/// </summary>
/// <param name="value">union struct value</param>
public TestEndianUnit(UInt16 value)
{
this.Value = value;
}
#endregion
}
}
SystemInfo.cs
// -----------------------------------------------------------------------
// <copyright file="SystemInfo.cs" Author="Yaping Xin">
// Helper class to get system information.
// </copyright>
// -----------------------------------------------------------------------
namespace TestEndian
{
using System;
/// <summary>
/// Helper class to get system information.
/// </summary>
public class SystemInfo
{
/// <summary>
/// This function get endianness of current running environment.
/// Return value: False -- Little endian
/// True -- Big endian
/// Reference: http://en.wikipedia.org/wiki/Endianness
///
/// For example: x86, x86-64 and Windows on PowerPC use little endian;
/// FreeBSD on PowerPC and SPARC use big endian.
/// </summary>
/// <returns>True indicates big endian.</returns>
public static unsafe bool IsBigEndian()
{
TestEndianUnit unit = new TestEndianUnit(0xFF00);
if (unit.Bytes[0] == 0x00 && unit.Bytes[1] == 0xFF)
{
return false;
}
else if (unit.Bytes[0] == 0xFF && unit.Bytes[1] == 0x00)
{
return true;
}
else
{
throw new ArithmeticException(
"Error occurs while judge system endian.");
}
}
}
}
需要注意的是:方法三的代码需要在Project中打开“unsafe”选项才可编译,如图:
参考文献:
- C Tips: How to tell if system is little endian or big endian? http://blog.csdn.net/xinyaping/article/details/7450920
- Endianness http://en.wikipedia.org/wiki/Endianness
- Big and Little Endian http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/endian.html