C# Tips: How to tell if system is little endian or big endian?

来源:互联网 发布:淘宝异地发货违规吗 编辑:程序博客网 时间:2024/05/22 08:06

上回书说到,如果用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结构

文件列表:

  1. TestEndianUnit.cs
  2. 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)

文件列表:

  1. TestEndianUnit.cs
  2. 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”选项才可编译,如图:




参考文献:

  1. C Tips: How to tell if system is little endian or big endian? http://blog.csdn.net/xinyaping/article/details/7450920
  2. Endianness http://en.wikipedia.org/wiki/Endianness
  3. Big and Little Endian http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/endian.html