大端模式、小端模式和C#反轉
A、C#大端模式和小端模式。
小端(little-endian)模式:低地址上存放低字節,高地址上存放高字節。
如0x11223344→ byte[] numBytes = new byte[]{ 0x44,0x33,0x22,0x11};
numBytes[0] = 0x44; //低地址存放低字節
numBytes[3] = 0x11; //高地址存放高字節
反之,高字節在前,低字節在後,則為大端模式。
反轉示例:
short num = 12;
byte[] bytes = BitConverter.GetBytes(s);
Array.Reverse(bytes); //bytes轉換為倒序(反轉),可實現大端小端的轉換
B、大端模式和小端模式。原文地址:https://blog.csdn.net/qqliyunpeng/article/details/68484497
作者: 李雲鵬([email protected])
版本號: 20170330
更新時間: <2017-04-06>
原創時間: <2017-03-30>
版權: 本文采用以下協議進行授權,自由轉載 - 非商用 - 非衍生 - 保持署名 | Creative Commons BY-NC-ND 3.0,轉載請註明作者及出處.
1. 概念簡介
不同的系統在存儲數據時是分大端(bit-endian)小端(little-endian)存儲的,比如,Inter x86、ARM核采用的是小端模式,Power PC、MIPS UNIX和HP-PA UNIX采用大端模式
小端模式用文字描述是,低地址上存放低字節,高地址上存放高字節。
假如有一個32位的數據 0x11223344,則在小端模式上的機器上存儲為如下的形式:
【1】0x11223344這個數中 0x11 是高字節(MSB),0x44是地字節(LSB)
【2】討論大小端的時候最小單位是字節
【3】內存的畫法中采用的是向上增長的
【3】可以將數據比作方向盤,順時鐘旋轉得到的在內存中的布局是小端存儲
至於大端模式用文字描述是,低地址上存放高字節,高地址上存放低字節。
2. 如何判斷
判斷的方法有很多種,下面將簡單的列舉幾種:
第一種方法:
[cpp] view plain copy
- /*
- * 1: little-endian
- * 0: big-endian
- */
- int checkEndian()
- {
- int a = 1;
- char *p = (char *)&a;
- return (*p == 1);
- }
【1】如果是大端,*p的結果是0
第二種方法:
[cpp] view plain copy
- /*
- * 1: little-endian
- * 0: big-endian
- */
- int checkEndian()
- {
- union w
- {
- int a;
- char b;
- } c;
- c.a = 1;
- return (c.b == 1);
- }
函數中打印方法:
[cpp] view plain copy
- printf("%s\n", checkEndian() ? "little-endian" : "big-endian");
3. 大端和小端的轉換
[cpp] view plain copy
- int big_litle_endian(int x)
- {
- int tmp;
- tmp = (((x)&0xff)<<24) + (((x>>8)&0xff)<<16) + (((x>>16)&0xff)<<8) + (((x>>24)&0xff));
- return tmp;
- }
4. 其他
1. 在通信的場合經常會遇到大端和小端的轉換的問題,比如tcp/ip 中,tcp/ip 中規定了自己傳輸的時候采用大端模式,當然相應的它也提供了很多函數來做支持。
如果主機是小端的模式,在跟網絡進行交互的時候經常要用到如下的函數
- htons —— 把unsigned short類型從 主機序 轉成 網絡字節序
- ntohs —— 把unsigned short類型從 網絡字節序 轉成 主機序
- htonl —— 把unsigned long類型從 主機序 轉成 網絡字節序
- ntohl —— 把unsigned long類型從 網絡字節序 轉成 主機序
- #if defined(_LINUX) || defined(_DARWIN)
- #include <netinet/in.h>
- #endif
- #ifdef WIN32
- #include <WINSOCK2.H>
- #endif
當一個系統要發送的數據是 0x12345678,以大端模式發送,則會先發送0x12.
2. 如何在64位ubuntu下同下編譯32位的程序?
需要先安裝32位的庫:sudo apt-get install libc6-dev-i386
然後在編譯的時候加上-m32選項。
C、C#實現反轉總結。原文地址:https://blog.csdn.net/chenfujun818/article/details/78654956
下面是C#版 反轉數組的幾種總結。
解決其他同行的轉換字符串而來。覺得很實用就整理了一下。
字符串版地址:http://m.blog.csdn.net/superit401/article/details/51318880
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//unity 必須引用 system.text 命名空間
using System.Text;
public class ArrayReverseTest : MonoBehaviour {
private List<int> _arrList = new List<int>{12,58,36,46,78,463,588,999};
void Start () {
PrintList();
Debug.Log(" ================ before ==============");
// _arrList = ArrayReverse();
// _arrList = BufferReverse();
// _arrList = StackReverse();
// _arrList = XORReverse();
RecursiveReverse(_arrList,0,_arrList.Count -1);
PrintList();
Debug.Log(" ================ after ==============");
}
//方法一 使用.net 自帶的Array.Reverse() 面試時不建議用
List<int> ArrayReverse()
{
_arrList.Reverse();
return _arrList;
}
// 方法二 使用緩存數組方式 取1/2 進行交換
List<int> BufferReverse()
{
int countList = _arrList.Count;
for(int i = 0;i < countList / 2 ;i++)
{
int temp = _arrList[i];
_arrList[i] = _arrList[countList - i - 1];
_arrList[countList - i - 1] = temp;
}
return _arrList;
}
//方法三 使用棧
List<int> StackReverse()
{
List<int> tempList = new List<int>();
tempList.Clear();
Stack stack = new Stack();
foreach(int value in _arrList)
{
stack.Push(value);//入棧
}
for(int i = 0;i < _arrList.Count;i++)
{
tempList.Add((int)stack.Pop());//出棧
}
return tempList;
}
//方法四 使用異或運算進行反轉
List<int> XORReverse()
{
int countList = _arrList.Count - 1;
for(int i = 0;i < countList;i++,countList--)
{
_arrList[i] ^= _arrList[countList];
_arrList[countList] ^= _arrList[i];
_arrList[i] ^= _arrList[countList];
}
return _arrList;
}
//方法五 使用遞歸 進行反轉
void RecursiveReverse(List<int> list,int left,int right)
{
if(left >= right)
return;
//轉換方式一
// int temp = list[left];
// list[left] = list[right];
// list[right] = temp;
//轉換方式二
list[left] ^= list[right];
list[right] ^= list[left];
list[left] ^= list[right];
RecursiveReverse(list,++left,--right);
}
void PrintList()
{
//使用stringBuilder 的好處不言自明了 反轉字符串的時候 它也是一種方式
StringBuilder strBuilder = new StringBuilder();
for(int i = 0,Max = System.Math.Min(_arrList.Count,_arrList.Count);i< _arrList.Count;i++)
{
strBuilder.Append(_arrList[i]);
strBuilder.Append(" ");
}
Debug.Log(" _arrlist = " + strBuilder);
}
}
字符串反轉的9種方法
1. 使用Array.Reverse方法
對於字符串反轉,我們可以使用.NET類庫自帶的Array.Reverse方法
public static string ReverseByArray(string original)
{
char[] c = original.ToCharArray();
Array.Reverse(c);
return new string(c);
}
2. 使用字符緩存
在面試或筆試中,往往要求不用任何類庫方法,那麽有朋友大概會使用類似下面這樣的循環方法
public static string ReverseByCharBuffer(this string original)
{
char[] c = original.ToCharArray();
int l = original.Length;
char[] o = new char[l];
for (int i = 0; i < l ; i++)
{
o[i] = c[l - i - 1];
}
return new string(o);
}
當然,聰明的同學們一定會發現不必對這個字符數組進行完全遍歷,通常情況下我們會只遍歷一半
public static string ReverseByCharBuffer2(string original)
{
char[] c = original.ToCharArray();
int l = original.Length;
for (int i = 0; i < l / 2; i++)
{
char t = c[i];
c[i] = c[l - i - 1];
c[l - i - 1] = t;
}
return new string(c);
}
ReverseByCharBuffer使用了一個新的數組,而且遍歷了字符數組的所有元素,因此時間和空間的開銷都要大於ReverseByCharBuffer2。
在Array.Reverse內部,調用了非托管方法TrySZReverse,如果TrySZReverse不成功,實際上也是調用了類似ReverseByCharBuffer2的方法。
if (!TrySZReverse(array, index, length))
{
int num = index;
int num2 = (index + length) - 1;
object[] objArray = array as object[];
if (objArray == null)
{
while (num < num2)
{
object obj3 = array.GetValue(num);
array.SetValue(array.GetValue(num2), num);
array.SetValue(obj3, num2);
num++;
num2--;
}
}
else
{
while (num < num2)
{
object obj2 = objArray[num];
objArray[num] = objArray[num2];
objArray[num2] = obj2;
num++;
num2--;
}
}
}
大致上我能想到的算法就是這麽多了,但是我無意間發現了StackOverflow上的一篇帖子,才發現這麽一個看似簡單的反轉算法實現起來真可謂花樣繁多。
3. 使用StringBuilder
使用StringBuilder方法大致和ReverseByCharBuffer一樣,只不過不使用字符數組做緩存,而是使用StringBuilder。
public static string ReverseByStringBuilder(this string original)
{
StringBuilder sb = new StringBuilder(original.Length);
for (int i = original.Length - 1; i >= 0; i--)
{
sb.Append(original[i]);
}
return sb.ToString();
}
當然,你可以預見,這種算法的效率不會比ReverseByCharBuffer要高。
我們可以像使用字符緩存那樣,對使用StringBuilder方法進行優化,使其遍歷過程也減少一半
public static string ReverseByStringBuilder2(this string original)
{
StringBuilder sb = new StringBuilder(original);
for (int i = 0, j = original.Length - 1; i <= j; i++, j--)
{
sb[i] = original[j];
sb[j] = original[i];
}
return sb.ToString();
}
以上這幾種方法按算法角度來說,其實可以歸結為一類。然而下面的幾種算法就完全不是同一類型的了。
使用棧
4. 棧是一個很神奇的數據結構。我們可以使用它後進先出的特性來對數組進行反轉。先將數組所有元素壓入棧,然後再取出,順序很自然地就與原先相反了。
public static string ReverseByStack(this string original)
{
Stack<char> stack = new Stack<char>();
foreach (char ch in original)
{
stack.Push(ch);
}
char[] c = new char[original.Length];
for (int i = 0; i < original.Length; i++)
{
c[i] = stack.Pop();
}
return new string(c);
}
兩次循環和棧的開銷無疑使這種方法成為目前為止開銷最大的方法。但使用棧這個數據結構的想法還是非常有價值的。
使用XOR
5. 使用邏輯異或也可以進行反轉
public static string ReverseByXor(string original)
{
char[] charArray = original.ToCharArray();
int l = original.Length - 1;
for (int i = 0; i < l; i++, l--)
{
charArray[i] ^= charArray[l];
charArray[l] ^= charArray[i];
charArray[i] ^= charArray[l];
}
return new string(charArray);
}
在C#中,x ^= y相當於x = x ^ y。通過3次異或操作,可以將兩個字符為止互換。對於算法具體的解釋可以參考這篇文章。
6. 使用指針
使用指針可以達到最快的速度,但是unsafe代碼不是微軟所推薦的,在這裏我們就不多做討論了
public static unsafe string ReverseByPointer(this string original)
{
fixed (char* pText = original)
{
char* pStart = pText;
char* pEnd = pText + original.Length - 1;
for (int i = original.Length / 2; i >= 0; i--)
{
char temp = *pStart;
*pStart++ = *pEnd;
*pEnd-- = temp;
}
return original;
}
}
7. 使用遞歸
對於反轉這類算法,都可以使用遞歸方法
public static string ReverseByRecursive(string original)
{
if (original.Length == 1)
return original;
else
return original.Substring(1).ReverseByRecursive() + original[0];
}
8. 使用委托,還可以使代碼變得更加簡潔
public static string ReverseByRecursive2(this string original)
{
Func<string, string> f = null;
f = s => s.Length > 0 ? f(s.Substring(1)) + s[0] : string.Empty;
return f(original);
}
但是委托開銷大的弊病在這裏一點也沒有減少,以至於我做性能測試的時候導致系統假死甚至內存益處。
使用LINQ
9. System.Enumerable裏提供了默認的Reverse擴展方法,我們可以基於該方法來對String類型進行擴展
public static string ReverseByLinq(this string original)
{
return new string(original.Reverse().ToArray());
}
大端模式、小端模式和C#反轉