上回书说到,如果用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
// ----------------------------------------------------------------------- // <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 } }
// ----------------------------------------------------------------------- // <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
// ----------------------------------------------------------------------- // <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 } }
// ----------------------------------------------------------------------- // <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”选项才可编译,如图:
参考文献: