• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            colorful

            zc qq:1337220912

             

            大端小端(Big- Endian和Little-Endian)

            1/ 網絡字節順序是TCP/IP中規定好的一種數據表示格式,它與具體的CPU類型、操作系統等無關,從而可以保證數據在不同主機之間傳輸時能夠被正確解釋,網絡字節順序采用big-endian排序方式。
            2/ 而我們常用的 x86 CPU (intel, AMD) 電腦是 little-endian,也就是整數的低位字節放在內存的低字節處。

            舉個例子吧。假定你的數據是0x1234,
            在網絡字節順序里 這個數據放到內存中就應該顯示成
            addr addr+1
            0x12 0x34
            而在x86電腦上,數據0x1234放到內存中實際是:
            addr addr+1
            0x34 0x12
            htons 的用處就是把實際主機內存中的整數存放方式調整成網絡字節順序。


            ------------------------------------------------------------------------------------------------------------

            大端小端(Big- Endian和Little-Endian)

            字節序(Endian),大端(Big-Endian),小端(Little-Endian) 圖文并茂

            http://www.shnenglu.com/tx7do/archive/2009/01/06/71276.html

             http://my.oschina.net/alphajay/blog/5478

            在 各種計算機體系結構中,對于字節、字等的存儲機制有所不同,因而引發了計算機 通信領 域中一個很重要的問題,即通信雙方交流的信息單元(比特、字節、字、雙字等等)應該以什么樣的順序進行傳送。如果不達成一致的規則,通信雙方將無法進行正 確的編/譯碼從而導致通信失敗。目前在各種體系的計算機中通常采用的字節存儲機制主要有兩種:Big-Endian和Little-Endian,下面先 從字節序說起。

             

            一、什么是字節序

            字節序,顧名思義字節的順序,再多說兩句就是大于一個字節類型的數據在內存中的存放順序(一個字節的數據當然就無需談順序的問題了)其實大部分人在實際的開 發中都很少會直接和字節序打交道。唯有在跨平臺以及網絡程序中字節序才是一個應該被考慮的問題。

            在所有的介紹字節序的文章中都會提到字 節序分為兩類:Big-Endian和Little-Endian,引用標準的Big-Endian和Little-Endian的定義如下:
            a) Little-Endian就是低位字節排放在內存的低地址端,高位字節排放在內存的高地址端
            b) Big-Endian就是高位字節排放在內存的低地址端,低位字節排放在內存的高地址端
            c) 網絡字節序:TCP/IP各層協議將字節序定義為Big-Endian,因此TCP/IP協議中使用的字節序通常稱之為網絡字節序。

            1.1 什么是高/低地址端

            首先我們要知道我們C程序映像中內存的空間布局情況:在《C專 家編程》中或者《Unix環境高級編程》中有關于內存空間布局情況的說明,大致如下圖:
            ----------------------- 最高內存地址 0xffffffff
            棧底

            棧頂

            -----------------------

            NULL (空洞)
            -----------------------

            -----------------------
            未初始 化的數據
            ----------------------- 統稱數據段
            初始化的數據
            -----------------------
            正 文段(代碼段)
            ----------------------- 最低內存地址 0x00000000

            以上圖為例如果我們在棧 上分配一個unsigned char buf[4],那么這個數組變量在棧上是如何布局的呢?看下圖:
            棧底 (高地址)
            ----------
            buf[3]
            buf[2]
            buf[1]
            buf[0]

            ----------
            棧頂 (低地址)

            1.2 什么是高/低字節

            現在我們弄清了高/低地址,接著考慮高/低字節。有些文章中稱低位字節為最低有效位,高位字節為最高有效位。如果我們有一個32位無符號整型0x12345678,那么高位是什么,低位又是什么呢? 其實很簡單。在十進制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進制也是如此。就拿 0x12345678來說,從高位到低位的字節依次是0x12、0x34、0x56和0x78
            高/低地址端和高/低字節都弄清了。我們再來回顧 一下Big-Endian和Little-Endian的定義,并用圖示說明兩種字節序:
            以unsigned int value = 0x12345678為例,分別看看在兩種字節序下其存儲情況,我們可以用unsigned char buf[4]來表示value:

            Big-Endian: 低地址存放高位,如下圖:
            棧底 (高地址)
            ---------------
            buf[3] (0x78) -- 低位
            buf[2] (0x56)
            buf[1] (0x34)
            buf[0] (0x12) -- 高位
            ---------------
            棧頂 (低地址)

            Little-Endian: 低地址存放低位,如下圖:
            棧底 (高地址)
            ---------------
            buf[3] (0x12) -- 高位
            buf[2] (0x34)
            buf[1] (0x56)
            buf[0] (0x78) -- 低位
            --------------
            棧 頂 (低地址)

             

            二、各種Endian

            2.1 Big-Endian

            計算機體系結構中一種描述多字節存儲順序的術語,在這種機制中最重要字節(MSB)存放在最低端的地址 上。采用這種機制的處理器有IBM3700系列、PDP-10、Mortolora微處理器系列和絕大多數的RISC處理器。
            +----------+
            | 0x34 |<-- 0x00000021
            +----------+
            | 0x12 |<-- 0x00000020
            +----------+
            圖 1:雙字節數0x1234以Big-Endian的方式存在起始地址0x00000020中

             在Big-Endian中,對于bit序列 中的序號編排方式如下(以雙字節數0x8B8A為例):
            bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
            +-----------------------------------------+
            val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
            +----------------------------------------+
            圖 2:Big-Endian的bit序列編碼方式

            2.2 Little-Endian

            計算機體系結構中 一種描述多字節存儲順序的術語,在這種機制中最不重要字節(LSB)存放在最低端的地址上。采用這種機制的處理器有PDP-11、VAX、Intel系列 微處理器和一些網絡通信設備。該術語除了描述多字節存儲順序外還常常用來描述一個字節中各個比特的排放次序。

            +----------+
            | 0x12 |<-- 0x00000021
            +----------+
            | 0x34 |<-- 0x00000020
            +----------+

            圖3:雙字節數0x1234以Little-Endian的方式存在起始地址0x00000020中

             在 Little-Endian中,對于bit序列中的序號編排和Big-Endian剛好相反,其方式如下(以雙字節數0x8B8A為例):

            bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
            +-----------------------------------------+
            val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
            +-----------------------------------------+
            圖 4:Little-Endian的bit序列編碼方式

            注2:通常我們說的主機序(Host Order)就是遵循Little-Endian規則。所以當兩臺主機之間要通過TCP/IP協議進行通信的時候就需要調用相應的函數進行主機序 (Little-Endian)和網絡序(Big-Endian)的轉換

            注3:正因為這兩種機制對于同一bit序列的序號編排方式恰 恰相反,所以《現代英漢詞典》中對MSB的翻譯為“最高有效位”欠妥,故本文定義為“最重要的bit/byte”。

            2.3 Middle-Endian

            除了Big-Endian和Little-Endian之外的多字節存儲順序就是Middle- Endian,比如以4個字節為例:象以3-4-1-2或者2-1-4-3這樣的順序存儲的就是Middle-Endian。這種存儲順序偶爾會在一些小 型機體系中的十進制數的壓縮格式中出現

            嵌入式系統開發者應該對Little-endian和Big-endian模式非常了解。采用 Little-endian模式的CPU對操作數的存放方式是從低字節到高字節,而Big-endian模式對操作數的存放方式是從高字節到低字節。 32bit寬的數0x12345678在Little-endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)為:

            內存 地址 0x4000 0x4001 0x4002 0x4003
            存放內容 0x78 0x56 0x34 0x12

             

            而在Big- endian模式CPU內存中的存放方式則為:

            內存地址 0x4000 0x4001 0x4002 0x4003
            存放內容 0x12 0x34 0x56 0x78

             

            三、Big-EndianLittle-Endian優缺點

            Big-Endian優點:靠首先提取高位字節,你總是可以由看看在偏移位置為0的字節來確定這個數字是 正數還是負數。你不必知道這個數值有多長,或者你也不必過一些字節來看這個數值是否含有符號位這個數值是以它們被打印出來的順序存放的,所以從二進制到十進制的函數特別有效。因而,對于不同要求的機器,在設計存取方式時就會不同。

            Little-Endian優點:提取一個,兩個,四個或者更長字節數據的匯編指令以與其他所有格式相同的方式進行:首先在偏移地址為0的地方提取最低位的字節,因為地址偏移和字節數是一對 一的關系,多重精度的數學函數就相對地容易寫了

            如 果你增加數字的值,你可能在左邊增加數字(高位非指數函數需要更多的數字)。 因此, 經常需要增加兩位數字并移動存儲器里所有Big-endian順序的數字,把所有數向右移,這會增加計算機的工作量。不過,使用Little- Endian的存儲器中不重要的字節可以存在它原來的位置,新的數可以存在它的右邊的高位地址里。這就意味著計算機中的某些計算可以變得更加簡單和快速。

            四、如何檢查處理器是Big-Endian還是Little-Endian?

            由于聯合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕松地獲得了CPU對內存采用Little- endian還是Big-endian模式讀寫。例如:
            int checkCPUendian(){
            union {
            unsigned int a;
            unsigned char b;           
            }c;
            c.a = 1;
            return (c.b == 1);      

            }   /*return 1 : little-endian, return 0:big-endian*/

             

            五、Big-EndianLittle-Endian轉 換

             

            現有的平臺上Intel的X86采用的是Little-Endian,而像 Sun的SPARC采用的就是Big-Endian。那么在跨平臺或網絡程序中如何實現字節序的轉換呢?這個通過C語言的移位操作很容易實現,例如下面的 宏:

            #if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)

            #define htons(A)   (A)
            #define htonl(A)     (A)
            #define ntohs(A)   (A)
            #define ntohl(A)    (A)

            #elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)

            #define htons(A)     ((((uint16)(A) & 0xff00) >> 8) | \
            (((uint16)(A) & 0x00ff) << 8))
            #define htonl(A)     ((((uint32)(A) & 0xff000000) >> 24) | \
            (((uint32)(A) & 0x00ff0000) >> 8) | \
            (((uint32)(A) & 0x0000ff00) << 8) | \
            (((uint32)(A) & 0x000000ff) << 24))
            #define ntohs htons
            #define ntohl htohl

            #else

            #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."

             

             

            網絡字節順序
            1、字節內的比特位不受這種順序的影響
            比如一個字節 1000 0000 (或表示為十六進制 80H)不管是什么順序其內存中的表示法都是這樣。

             

            2、大于1個字節的數據類型才有字節順序問題
            比如 Byte A,這個變量只有一個字節的長度,所以根據上一條沒有字節順序問題。所以字節順序是“字節之間的相對順序”的意思。


            3、大于1個字節的數據類型的字節順序有兩種
            比如 short B,這是一個兩字節的數據類型,這時就有字節之間的相對順序問題了。
            網絡字節順序是“所見即所得”的順序。而Intel類型的CPU的字節順序與此相反。
            比如上面的 short B=0102H(十六進制,每兩位表示一個字節的寬度)。所見到的是“0102”,按一般數學常識,數軸從左到右的方向增加,即內存地址從左到右增加的話,在內存中這個 short B的字節順序是:
            01 02
            這就是網絡字節順序。所見到的順序和在內存中的順序是一致的!
            假設通過抓包得到網絡數據的兩個字節流為:01 02

            而相反的字節順序就不同了,其在內存中的順序為:02 01

            如果這表示兩個 Byte類型的變量,那么自然不需要考慮字節順序的問題。如果這表示一個 short 變量,那么就需要考慮字節順序問題。根據網絡字節順序“所見即所得”的規則,這個變量的值就是:0102

            假設本地主機是Intel類型的,那么要表示這個變量,有點麻煩:
            定義變量 short X,字節流地址為:pt,按順序讀取內存是為x=*((short*)pt);
            那么X的內存順序當然是 01 02按非“所見即所得”的規則,這個內存順序和看到的一樣顯然是不對的,所以要把這兩個字節的位置調換。調換的方法可以自己定義,但用已經有的API還是更為方便。

            網絡字節順序與主機字節順序
            NBO 與HBO 網絡字節順序NBO(Network Byte Order):按從高到低的順序存儲,在網絡上使用統一的網絡字節順序,可以避免兼容性問題。主機字節順序(HBO,Host Byte Order):不同的機器HBO不相同,與CPU設計有關計算機數據存儲有兩種字節優先順序:高位字節優先和低位字節優先Internet上數據以高位字節優先順序在網絡上傳輸,所以對于在內部是以低位字節優先方式存儲數據的機器,在Internet上傳輸數據時就需要進行轉換。

            htonl()
            簡述:
                將主機的無符號長整形數轉換成網絡字節順序。
                #include <winsock.h>
                u_long PASCAL FAR htonl( u_long hostlong);
                hostlong:主機字節順序表達的32位數。
            注釋:
                本函數將一個32位數從主機字節順序轉換成網絡字節順序。
            返回值:
                htonl()返回一個網絡字節順序的值。

            inet_ntoa()
            簡述:
            將網絡地址轉換成“.”點隔的字符串格式。
            #include <winsock.h>
            char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
            in:一個表示Internet主機地址的結構。
            注釋:
            本 函數將一個用in參數所表示的Internet地址結構轉換成以“.” 間隔的諸如“a.b.c.d”的字符串形式。請注意inet_ntoa()返回的字符串存放在WINDOWS套接口實現所分配的內存中。應用程序不應假設 該內存是如何分配的。在同一個線程的下一個WINDOWS套接口調用前,數據將保證是有效。
            返回值:
            若無錯誤發生,inet_ntoa()返回一個字符指針。否則的話,返回NULL。其中的數據應在下一個WINDOWS套接口調用前復制出來。

            網 絡中傳輸的數據有的和本地字節存儲順序一致,而有的則截然不同,為了數據的一致性,就要把本地的數據轉換成網絡上使用的格式,然后發送出去,接收的時候也 是一樣的,經過轉換然后才去使用這些數據,基本的庫函數中提供了這樣的可以進行字節轉換的函數,如和htons( ) htonl( ) ntohs( ) ntohl( ),這里n表示network,h表示host,htons( ) htonl( )用于本地字節向網絡字節轉換的場合,s表示short,即對2字節操作,l表示long即對4字節操作。同樣ntohs( )ntohl( )用于網絡字節向本地格式轉換的場合。

             #endif

            posted @ 2012-05-17 10:13 多彩人生 閱讀(3183) | 評論 (0)編輯 收藏

            關于跨平臺數據類型的幾篇博文 有些矛盾

            c++ 中關于int,unsigned int , short的跨平臺移植

            int類型比較特殊,具體的字節數同機器字長和編譯器有關。如果要保證移植性,盡量用__int16 __int32 __int64吧
            __int16、__int32這種數據類型在所有平臺下都分配相同的字節。所以在移植上不存在問題。
            所謂的不可移植是指:在一個平臺上編寫的代碼無法拿到另一個平臺上運行時,不能達到期望的運行結果
            例如:在32為平臺上(所謂32位平臺是指通用寄存器的數據寬度是32)編寫代碼,int 類型分配4個字節,而在16位平臺是則分配2個字節,那么在16位上編譯出來的exe,
            其中是為int分配2字節,而在32位平臺上運行時,會按照4個字節來解析,顯然會出錯誤的!!

            而對于非int行,目前為止,所有的類型分配的字節數都是兼容的,即不同平臺對于同一個類型分配相同的字節數!!

            建議:在代碼中盡量避免使用int類型,根據不同的需要可以用short,long,unsigned int 等代替。

            下面是各個類型一覽表【轉】

            64位指的是cpu通用寄存器的數據寬度是64位的。

            數據類型名稱字節數別名取值范圍
            int*signed,signed int操作系統決定,即與操作系統的"字長"有關
            unsigned int*unsigned由操作系統決定,即與操作系統的"字長"有關
            __int81char,signed char–128 到 127
            __int162short,short int,signed short int–32,768 到 32,767
            __int324signed,signed int–2,147,483,648 到 2,147,483,647
            __int648–9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
            bool1false 或 true
            char1signed char–128 到 127
            unsigned char10 到 255
            short2short int,signed short int–32,768 到 32,767
            unsigned short2unsigned short int0 到 65,535
            long4long int,signed long int–2,147,483,648 到 2,147,483,647
            long long8none (but equivalent to __int64)–9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
            unsigned long4unsigned long int0 到 4,294,967,295
            enum*由操作系統決定,即與操作系統的"字長"有關
            float43.4E +/- 38 (7 digits)
            double81.7E +/- 308 (15 digits)
            long double81.7E +/- 308 (15 digits)
            wchar_t2__wchar_t0 到 65,535
            類型標識符類型說明長度
            (字節)
            范圍備注
            char字符型1-128 ~ 127-27 ~ (27 -1)
            unsigned char無符字符型10 ~ 2550 ~ (28 -1)
            short int短整型2-32768 ~ 327672-15 ~ (215 - 1)
            unsigned short int無符短整型20 ~ 655350 ~ (216 - 1)
            int整型4-2147483648 ~ 2147483647-231 ~ (231 - 1)
            unsigned int無符整型40 ~ 42949672950 ~ (232-1)
            float實型(單精度)41.18*10-38 ~ 3.40*10387位有效位
            double實型(雙精度)82.23*10-308 ~ 1.79*1030815位有效位
            long double實型(長雙精度)103.37*10-4932 ~ 1.18*10493219位有效位


            發表于 2011-04-15 14:02 阿π 閱讀(1812) 評論(4)  編輯 收藏 引用 所屬分類: 其它
             
            評論
            # re: c++ 中關于int,unsigned int , short的跨平臺移植
            C99應該用int**_t
            空明流轉 評論于 2011-04-15 16:14  回復  更多評論    
            # re: c++ 中關于int,unsigned int , short的跨平臺移植
            我也做過移植.
            影響中16位平臺,多用C來開來,多是嵌入式開發.
            32、64位在PC、服務器級較多,目前16位已很少.
            我個人認為int型相于對long類型要安全.
            long類型在windows-64下,仍是32字節;
            但在LINUX-64下long和指針是相當的,已升級到了64字節,
            如果結構體中使用long,結果大小有變,windows64下做的資源在linux下64處理,會有問題,
            最常見的資源頭大小就一致.
            如果是大型項目,還是建立自己的一套低層基本數據類型封裝方為上策.
            bbxyard 評論于 2011-04-15 23:33  回復  更多評論    
            # re: c++ 中關于int,unsigned int , short的跨平臺移植[未登錄]
            lz說的不對,應該用int8_t, int16_t,int32_t, int64_t, uintXX_t 等等。而以兩個下劃線開頭的那種類型是微軟自己的東西,是不可以移植的。
            Alex 評論于 2011-04-16 23:52  回復  更多評論    
            # re: c++ 中關于int,unsigned int , short的跨平臺移植
            原來這么復雜啊,分析的好詳細,頂!
            free keylogger 評論于 2011-09-08 22:46  回復  更多評論    
             

            ============================================================

            C/C++ 32位機器和64位機器 差異問題總結 跨平臺 移植問題 語言編程需要注意的64位和32機器的區別  

            2011-09-28 22:39:45|  分類: C++ |  標簽:c++  64位機  數據類型   |字號 訂閱

            轉載自:http://hi.baidu.com/jrckkyy/blog/item/61d7869b264d64aec8eaf411.html

            #include <stddef.h>

            OS version:Red Hat Enterprise Linux Server release 5.3 (Tikanga) Linux 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 EST 2008 x86_64 x86_64 x86_64 GNU/Linux

            size_t本身一個作用就是避免考慮64還是32。64位下Long和指針是64位的

            size_tm_unNo;

            sprintf(path,"%u",m_unNo); //這句在32位機器上正常 64位機器上會編譯警告:“警告:格式 ‘%u’ 需要類型 ‘unsigned int’,但實參 4 的類型為 ‘size_t’”

            %u 對應 unsigned int在64位機器上還是32位,而size_t已經變成64位了。

            char* 指針在64位下是64位

            m_pMem = new char[nSize];
            int off = (int)m_pMem%nAlign; // 在 32位編譯正常,在64位機器上編譯報錯:“ 錯誤:從 ‘char*’ 到 ‘int’ 的轉換損失精度”

            改為就可以達到兼容效果了int off = (uint64_t)m_pMem%nAlign; // 因為int在64位下仍為32位,char×已經變位64位了。

             

             

             

             

            一、數據類型特別是int相關的類型在不同位數機器的平臺下長度不同。C99標準并不規定具體數據類型的長度大小,只規定級別。作下比較:

            16位平臺

            char         1個字節8位

            short        2個字節16位

            int            2個字節16位

            long         4個字節32位

            指針         2個字節

            32位平臺

            char         1個字節8位

            short        2個字節16位

            int            4個字節32位

            long         4個字節

            long long 8個字節

            指針         4個字節

            64位平臺

            char         1個字節

            short        2個字節

            int            4個字節

            long         8個字節(區別)

            long long 8個字節

            指針        8個字節(區別)

            二、編程注意事項

            為了保證平臺的通用性,程序中盡量不要使用long數據庫型。可以使用固定大小的數據類型宏定義:

            typedef signed char       int8_t

            typedef short int             int16_t;

            typedef int                      int32_t;

            # if __WORDSIZE == 64
            typedef long int              int64_t;
            # else
            __extension__
            typedef long long int      int64_t;

            #endif

            三、使用int時也可以使用intptr_t來保證平臺的通用性,它在不同的平臺上編譯時長度不同,但都是標準的平臺長度,比如64位機器它的長度就是8字節,32位機器它的長度是4字節,定義如下:

            #if __WORDSIZE == 64
            typedef long int                intptr_t;
            #else
            typedef int                        intptr_t;
            #endif
            編程中要盡量使用sizeof來計算數據類型的大小

            以上類型定義都有相應的無符號類型。

            另 外還有ssize_t和size_t分別是unsigned和signed size of computer word size。它們也是表示計算機的字長,在32位機器上是int型,在64位機器上long型,從某種意義上來說它們等同于intptr_t和 uintptr_t。它們在stddef.h里面定義。需要注意的是socket的accept函數在有些操作系統上使用size_t是不正確的,因為 accept接收的int*類型,而size_t可能是long int 類型。后來BSD使用sock_t來替代它。

            posted @ 2012-05-15 17:00 多彩人生 閱讀(1589) | 評論 (0)編輯 收藏

            編寫跨平臺的軟件入門——有關字節對齊

            一,             為什么要跨平臺?

            你想過把你的 Windows 上編寫的程序在 Linux 編譯運行嗎,以及在 Mac 或其他 OS 上運行等等?反過來也一樣?這就需要涉及到跨平臺編程知識。這里需要注意的是,平時很多在一個平臺運行的程序在跨平臺的時候變的不再正確。

            Java 并非真的是跨平臺的開發環境,它是運行在它自己的平臺上。這里主要關注 C 和 C++ 的跨平臺開發。

            下面主要就幾個方面來討論跨平臺編程的注意事項:

            1.  字節序

            2.  字節填充

            3.  其他

            二,             字節序

            大家都知道計算機使用兩種字節序,一種是 little-endian ,另一種是 big-endian 。這主要是由于當前流行的 CPU 之間的差異造成的,基本上是 IBM-PowerPC 使用的大序,而其他 CPU 使用的小序。

            這里先來介紹一下 little-endian 和 big-endian 之間的具體差異。

            X86 指 令集合使用小序( little-endian )字節順序;這就意味著多個字節值的最重要字節在地址的最低位。小序很早就使用,因為硬件容易實現,但和今天的制造商技術有點不同;但在第一代 IBM PC 機的 Vaxen 和 8086 處理器使用是它如此流行的主要原因。

            看一個例子:

            short example[2] = {0x0001,0x0302};

             

            按照 16 進制的形式來顯示上面數據在內存中的存儲方式:

            01 00 02 03

            我們看到對于數組的第一個元素,高 8 位應該是 0 ,而最終存儲的時候是在低 8 位的后面。

            而 另一方面 PowerPC 和 Sparc 芯片是 big-endian 的,也就是說,最重要的字節存儲在較低的地址。對于 CPU 需要額外的電路實現這個功能,但對于今天的處理器技術與緩存控制技術相比較顯的微不足道。使用 BIG-ENDIAN 的最大好處是在使用低級調式器時比較容易理解數據的存儲,同樣對于文件十六進制 DUMP 或網絡 Sniffer 顯示也是一樣的。

            對于 BIG-ENDIAN ,上面的例子中內存如下表示:

            00 01 03 02

            這里需要注意的是:由于 BIG-ENDIAN 格式的 RAW 數據比較容易調式,如果我們有機會設計一個新的文件格式,那么使用 BIG-ENDIAN 格式,而不是根據 CPU 架構來決定。

            下面看幾個關于字節序的問題:

            1.  Long 型指針和 char 指針之間的轉換

            看下面這段代碼

            unsigned long value = 0x03020100;

            unsigned long *ptr = &value;

            unsigned char charVal;

            charVal = *(unsigned char *)ptr;

            程序的含義比較簡單,主要是從一個指向 long 的指針強制轉換為一個指向 char 的指針,這里假設指針指向的是最不重要的字節地址。

            在一個 little-endian 處理器上, charVal 是 0 ,而在一個 big-endian 處理器上, charVal 的值是 3 。這樣的問題是最難以發現的問題之一。

            為了避免這個錯誤,使用一個臨時變量可以解決這個問題,如下:

            unsigned long temp = *ptr;

            charVal = (unsigned char)temp;

            上面的第二行代碼就保證將在任何架構上都將最不重要的字節傳遞給 charVal ;編譯器處理具體的細節。

            2.  讀寫文件和寫網絡數據

            在從文件讀數據或寫數據到文件的時候以及網絡,對于字節順序的處理一定要小心;一定記住不能將多個字節的數據寫到文件或網絡上;例如:

            long val = 1;

            int result = write(fileDes,&val,sizeof(val));

            這段代碼在 little-endian 和 big-endian 機器上執行的結果是不一樣的,如果讀數據的時候使用如下代碼:

            long val ;

            int result = read(fileDes,&val,sizeof(long));

            如果這兩段代碼分別位于 little-endian 和 big-endian 機器上,那么最終得到的 val 不是 1 ,而是 0x01000000 。

            解決多字節的讀寫有很多辦法,這里提供兩種。

            方法 1 :

            寫的代碼

            long val = 1;

            char buf[4];

            buf[0] = 0xff&val;

            buf[1] = (0xff00&val)>>8;

            buf[2] = (0xff0000&val)>>16;

            buf[3] = (0xff000000&val)>>24;

            int result = write(fileDes,buf,4);

            讀的代碼

            long val;

            char buf[4];

            int result = read(fileDes,buf,4);

            val = buf[0]|(buf[1]<<8)|(buf[2]<<16)|(buf[3]<<24);

            3.  運行時檢查字節順序

            bool gIsBigEndian;

            void InitializeEndianFlag()

            {

            Short one = 1;

            Char *cp = (char *)&one;

            If(*cp == 0)

                gIsBigEndian = true;

            else

                gIsBigEndian = false;

            return ;

            }

            4.  字節交換對性能的影響

            由于字節順序的問題導致在處理的時候需要進行字節交換或類似 2 中方法 1 的處理,這里稱為交換。通常情況下,做字節順序的交換并不影響,因為交換兩個字節或四個字節值只需要很少的 CPU 指令,并且完全可以在寄存器中執行。

            但如果有很多數據需要交換,例如:一個 1024*768 位圖的圖像,在這么大的循環中執行是影響性能的。

            另外對于 3 的運行時檢查字節序的代碼要查看具體的位置。如果僅僅調用一次或幾次,不會影響性能,如果對于上面的這個循環中調用,對性能的影響是顯著的,這個時候可以使用一個預編譯宏來分別處理。例如:

            #ifdef BIG_ENDIAN//big-endian

            #else//little-endian

            #endif//BIG_ENDIAN

             

            三,             字節填充

            另一個寫可移植代碼的注意點是結構體的字節對齊和填充。通常,在單個平臺上,如果需要保存一個結構體到文件,那么是作為一個整體寫到文件的,如下:

            struct myStruct{

            char theChar;

            long theLong;

            };

            struct myStruct foo;

            foo.the Char = 1;

            foo.theLong = 2;

            如果我們已經將數據按照 big-endian 進行了交換,然后直接將整個結構體寫到文件中。那么什么樣的數據會被寫到磁盤上呢?

            int result = write(fileDes, &foo, sizeof(foo));

            實際上我們不知道具體寫了什么數據,因為我們還不知道這個代碼在什么平臺上運行;實際上上面的 code 中會將垃圾數據寫到文件里,垃圾數據多少由 foo 分配到的內存決定的。

            一種可能我們認為的情況是:

             01 00 00 00 02

            但我們可能得到的這樣的數據:

            01 f 8 00 00 00 02

            甚至是:

            01 e6 a7 20 00 00 00 02

            這里到底發生了什么? sizeof(foo) 是編譯器和處理器依賴的。

            有 些處理器不能從某些位置讀或寫多個字節;幾乎所有的都不能從奇數地址來讀數據。通常他們只讀那些是 sizeof ( value )倍數的地址;對于四個字節只能讀地址是 4 個字節的倍數,對于 2 個字節的 short 只能讀兩個字節倍數的地址。如果不遵從這個字節對齊的規律,處理器會拋出一個異常并且終止程序,有些系統上會鎖定機器(如果發生在 kernel 中)。

            有 時,讀沒有對齊的數據需要花費額外的時間。例如: PowerPC 能夠讀任何偶數地址,但對于那些不能被 4 整除的地址需要耗費額外的總線周期。為了讀一個 long 數值( value )在 2 整除而不是 4 整除的地址,它將讀四個字節并包括需要讀的值的上面兩個字節,拋棄 2 個字節,然后讀另外四個包含 value 低 2 個字節的字節,同樣拋棄另外兩個。這與讀 4 個字節對齊的地址相比需要多訪問一次緩存。

            為了達到字節對齊的目的,編譯器會插入未命名的填充字節到結構體中。至于插入幾個字節是通過編譯器和 OS 或庫內存分配器一起決定的。

            在 Windows VC 編譯器中,可以使用 #pragma 來指定字節對齊的方式。

            總而言之,在定義結構的時候要按照字節邊界對齊來定義,一般按照 4 個字節,如果不夠就需要增加填充字段。

            另外對于結構體寫文件或輸出到網絡上,最好的辦法是按照成員來逐個寫入或發送,這可以避免將垃圾數據存放到文件中或傳輸到網絡上。

             

            四,             其他

            下面是幾個筆者在實際編寫代碼中發生過的錯誤,這里與大家一道分析一下。

            1.         示例 1 :

            for(int i = 0;i<1000;i++)

            {

               ….

            }

            ...

            for(int i = 0;i<1000;i++)

            {

            ...

            }

            上面這段代碼是很普通的 C++ 代碼,但這段代碼不一定可以在所有的編譯器中都能編譯通過。主要的原因在于變量 i 的聲明。

            C++ 標 準說:在 for 循環內部聲明的變量在 for 結束的時候無效,因此可以連續使用再次在 for 循環中使用該記數器變量。但很不幸的是很多編譯器都提供編譯選項來讓你覺得變量是否在 for 循環以后仍然有效。 VC 中默認編譯選項 /Ze 用來指定 for 循環變量的局部性,但并非所有的編譯器都是將這個選項作為默認編譯參數;所以為了能讓你的代碼可以在任意平臺編譯通過,使用 C 風格的會有保證一點;如下:

            int i = 0;

            for(i = 0;i<1000;i++)

            {

               ….

            }

            ...

            for(i = 0;i<1000;i++)

            {

            ...

            }

             

            2.         示例 2 : int 型變量的使用

            Int 型變量是一個奇怪的東西,它在 16 位機器上是 2 個字節,在 32 位機上是 4 個字節;將來可能在 64 位機上是 8 個字節。所以如果你的代碼中有對 int 的使用,而你想代碼可以在很多平臺上運行,那么一定要注意了。看一下下面的情況:

            for(int i = 0;i<65540;i++)

            {

               ….

            }

            這個代碼可能在不同的平臺上得到不同的結果。如果這個代碼是在 16 位機器上運行,那么得到的結果與 32 位機器上可能不同。

            同樣在使用 int 型變量寫文件和輸出到網絡時都要小心這個問題。最好的辦法是,在這些情況下不要使用 int 型變量; int 型變量僅僅在程序內部使用。

            3.         關于 Bit field 的問題

            在 C 語法中有 bit field 的語法,可以根據需要來定義一個符號具體占用的 bit 數,例如:

            typedef struct tagTest
            {
               char a:4;
               char b:2;
               char c:2;
            }TagTest,*PTagTest;

            實際上 tagTest 的字節數是 1 個字節,成員 a 占用 4 位, b 和各占用兩位。這樣的好處是可以針對每個成員賦值而設置指定的位的值,例如:

            tagTest myTest;
            myTest.a = 10;
            myTest.b = 2;
            myTest.c = 1;

            假如你在 Windows 上是使用 VC 來編譯連接上面的程序,不管如何處理,你不會發生任何問題。但現在我們假設將 myTest 放入緩沖區中,然后在 MAC 機器上取出來,那么會發生什么來?看代碼:

            Windows:

            char buf[10];

            buf[0] = myTest;

            buf[2]=...

            int result = send(fd,buf,10,..);

             

            MAC:

            char buf[10];

            int ret = 0;

            int result = recv(fd,buf,10,..);

            PTagTest pTest = (PTagTest)&buf[0];

             

            if(pTest->a == 10)

               ret = 1;

            else

                ret = 0;

            ...

            那么 ret 的值是什么呢?我們期望是 1 但,結果不是 1 。如果你通過調試器來觀察一下 pTest 各成員的值你發現:

            pTest->a = 6; pTest->b =2 ; pTest->c =2;

            細 心的讀者可能發現這里的問題所在,原因在于不同的編譯器對 bit field 進行了不同的處理。在 Windows 平臺上, c 被放在字節的最高兩位,而 a 被放在字節的最低 4 位,在 MAC 上正好相反。但一定要注意,這是編譯器行為,而不是數據在傳輸過程中發生了字節的位交換。在 Windows 發送到網絡的時候, buf[0] 的內容二進制表示為:

            01 10 1010

            在 MAC 上 recv 之后, buf[0] 的內容仍然與上面的相同。

            為了避免這個問題,請不要在寫文件或網絡輸出的時候使用 BIT FILED 語法,如果一定要使用請注意編譯器對位處理的區別。

            n         五 小結

            其 實實際工作中,大家認為自己的代碼都不需要在多個平臺上運行,而認為跨平臺編碼與自己無關;其實不然,好的編碼習慣是慢慢養成的,如果大家都知道這些跨平 臺編碼的細節,在開始寫代碼的時候就開始避免這樣的問題,一旦有一天我們的代碼需要跨平臺運行或一點我們要寫跨平臺代碼時,我們就不會無從下手,而是順其 自然,因為我們已經具備了這樣的習慣。

            當然這里的介紹只是一個開始,跨平臺編碼涉及的問題還很多,由于筆者經驗的限制不能一一描述。


            本文引用通告地址:http://lionwq.spaces.eepw.com.cn/articles/trackback/item/19180

            posted @ 2012-05-15 16:21 多彩人生 閱讀(508) | 評論 (0)編輯 收藏

            Winscp腳本同步文件

            # winscp.exe /console /script=sample.txt
            # Automatically answer all prompts negatively not to stall
            # the script on errors
            # option echo  on|off
            option echo off
            # option batch on|off|abort|continue
            option batch on
            # option confirm  on|off
            option confirm off
            # option transfer  binary|ascii|automatic
            # option synchdelete  on|off
            # option exclude clear | <mask>[;<mask2>...]
            # option include clear | <mask>[;<mask2>...]
            # open [ sftp|ftp|scp:// ][ <user> [ :password ] @ ] <host> [ :<port> ]
            # open user:password@example.com
            # Connect  
            open  USER:PASS@IP:PORT
            # Change remote directory
            # cd /home/user              #遠程工作目錄
            cd REMOTE PATH
            # Change local directory
            # set to Self's working dir 
            lcd LOCAL PATH                   #本地工作目錄
            # Force binary mode transfer
            option transfer binary
            # Download file to the local directory d:\
            # get examplefile.txt d:\
            # option synchdelete  on|off
            option synchdelete off       #是否同步刪除  
            # option include clear | <mask>[;<mask2>...]
            # option include /2008-*-*/;/2009-*-*/;/2010-*-*/;/2011-*-*/;/2012-*-*/;/2013-*-*/
            # synchronize local|remote|both [ <local directory> [ <remote directory> ] ] 
            # 傳輸方式:Local為遠程至本地,remote為本地到遠程,both雙向傳輸
            synchronize local  
            # Disconnect
            close
            # Exit WinSCP
            exit


            ======================================================
            #清除上面的注釋和個人理解了一下
            option echo off
            option batch on
            option confirm off
            option transfer binary
            option synchdelete off
            #只同步 *.h *.hpp *.cpp, 清除mask用命令:option include clear  
            option include "*.h; *.hpp; *.cpp; */"
            open scp://zc:123@192.168.1.128

            #請確保/home/zc/project/doloio 已存在
            cd /home/zc/project/doloio
            lcd E:\zc\test\doloio
            synchronize remote

            close
            exit

            posted @ 2012-05-15 10:57 多彩人生 閱讀(1017) | 評論 (0)編輯 收藏

            關于boost::thread 的一件怪事

            本想測試printf的線程安全的,結果發現boost::thread的一件有趣的事,見代碼
            #include <cstdio>
            #include 
            <boost/thread.hpp>
            #include 
            <boost/bind.hpp>

            int fun1()
            {
               
            for(int i=0; i<10; i++)
                  printf(
            "哈哈哈哈哈哈\n");
               
            return 0;
            }

            int fun2(int count)
            {
               
            for(int i=0; i<count; i++)
                  printf(
            "呵呵呵呵呵呵\n");
               
            return 0;
            }

            int main()
            {
               boost::thread(fun1);     
            // 不以打印
               boost::thread(fun2, 10); // 可以打印
               boost::thread t(fun1);   // 可以打印

               getchar();
               
            return 0;
            }
            不知什么原因,知道的可以告訴我嗎

            posted @ 2012-05-14 21:50 多彩人生 閱讀(339) | 評論 (0)編輯 收藏

            too many files open

            在ubuntu上開了服務端,在window上開了2000個連接去連server. 結果提示 too many files open錯誤:
            解決方法是: ulimit -n 4096
            {
              個人體會:注意,一定要在同一個terminal 下運行這個命令
               很容易找到這個解決方法,于是我打開了另一個terminal, 輸入了這個命令,哈哈,結果當然還是不行,原來ulimit -n 4096只是改變當前terminal的  limit
               Note this has no much relation to system max files (/proc/sys/fs/file-max).
            }

            網上相關資料
            -----------------------------------------------------------------------------------------------

            I had similar problem. Quick solution is :

            ulimit -n 4096

            explanation is as follows - each server connection is a file descriptor. In CentOS, Redhat and Fedora, probably others, file user limit is 1024 - no idea why. It can be easily seen when you type: ulimit -n

            Note this has no much relation to system max files (/proc/sys/fs/file-max).

            In my case it was problem with Redis, so I did:

            ulimit -n 4096 redis-server -c xxxx

            in your case instead of redis, you need to start your server.

            ----------------------------------------------------------------------------------------------------

            linux下Too many open files問題

            2011-01-21 14:42:13
            執行:ulimit -n
            應該會顯示默認值1024
            執行:ulimit -n 8192
            但是ulimit直接修改的數字,在系統重啟后會重置,所以還要修改:
            1、/etc/security/limits.conf,在里面加上:
            * soft nofile 8192
            * hard nofile 20480
            2、/etc/pam.d/login,里面加上:
            session required /lib/security/pam_limits.so

            ----------------------------------------------------------------------------------------------------
            ps:這個有好多知識點可以學
            分類: AIX


            登陸數據庫出現錯誤:ORA-12537: TNS:connection closed
            于是登陸操作系統
            [root@CCN-BJ-3-578 ~]# su - oracle
            su: /bin/bash: Too many open files in system
            [root@CCN-BJ-3-578 ~]#
            檢查報警日志沒有發現任何錯誤。
            [root@CCN-BJ-3-578 .ssh]# ulimit -a
            core file size          (blocks, -c) 0
            data seg size           (kbytes, -d) unlimited
            file size               (blocks, -f) unlimited
            pending signals                 (-i) 1024
            max locked memory       (kbytes, -l) 32
            max memory size         (kbytes, -m) unlimited
            open files                      (-n) 1024
            pipe size            (512 bytes, -p) 8
            POSIX message queues     (bytes, -q) 819200
            stack size              (kbytes, -s) 10240
            cpu time               (seconds, -t) unlimited
            max user processes              (-u) 73728
            virtual memory          (kbytes, -v) unlimited
            file locks                      (-x) unlimited
            [root@CCN-BJ-3-578 .ssh]#
            查看最大可以打開的文件數量
            [root@CCN-BJ-3-578 fs]# cat /proc/sys/fs/file-max
            65536
            查看各個進程打開的文件數據量
            [root@CCN-BJ-3-578 home]# lsof -n |awk '{print $2 " " $3}'|sort|uniq -c |sort -nr|more
              64387 18885 oracle
                 56 2669 oracle
                 53 2667 oracle
                 50 2693 oracle
                 。。。
            18885 明顯異常

            [root@CCN-BJ-3-578 ~]# ps -ef|grep 18885
            oracle   18885     1  0 Jan24 ?        00:00:19 ./linux
            root     10241 10049  0 13:45 pts/2    00:00:00 grep 18885
            發現oracle用戶在執行一個linux文件
            查找該文件
            [root@CCN-BJ-3-578 home]# find / -name linux
            /u01/app/oracle/product/10.2.0/db_1/jdk/include/linux
            /u01/app/oracle/product/10.2.0/db_1/oui/lib/linux
            /usr/java/jdk1.5.0_11/sample/jnlp/jreinstaller/build/linux
            /usr/java/jdk1.5.0_11/include/linux
            /usr/java/jdk1.5.0_11/demo/jvmti/hprof/src/linux
            /usr/X11R6/lib/Server/include/linux
            /usr/X11R6/lib/Server/modules/linux
            /usr/X11R6/lib/Server/modules/drivers/linux
            /usr/X11R6/lib/Server/modules/input/linux
            /usr/X11R6/lib/modules/linux
            /usr/X11R6/lib/modules/drivers/linux
            /usr/X11R6/lib/modules/input/linux
            /usr/share/terminfo/l/linux
            /usr/share/doc/ntp-4.2.0.a.20040617/build/hints/linux
            /usr/share/systemtap/runtime/relayfs/linux
            /usr/include/linux
            /usr/src/kernels/2.6.9-22.EL-hugemem-i686/include/linux
            /usr/src/kernels/2.6.9-22.EL-hugemem-i686/include/config/logo/linux
            /usr/src/kernels/2.6.9-22.EL-i686/include/linux
            /usr/src/kernels/2.6.9-22.EL-i686/include/config/logo/linux
            /usr/src/kernels/2.6.9-22.EL-smp-i686/include/linux
            /usr/src/kernels/2.6.9-22.EL-smp-i686/include/config/logo/linux
            /usr/lib/perl5/5.8.5/i386-linux-thread-multi/linux
            /usr/lib/bcc/include/linux
            /usr/lib/dietlibc/include/linux
            /home/oracle/.ssh/ /linux
            由于其它都是root用戶的,可以確定是/home/oracle/.ssh/ /linux正在執行
            [root@CCN-BJ-3-578 ~]# cd /home/oracle/.ssh/
            [root@CCN-BJ-3-578 .ssh]# cd " "
            [root@CCN-BJ-3-578  ]# pwd
            /home/oracle/.ssh/
            [root@CCN-BJ-3-578  ]# ll
            總用量 1572
            -rwxr-xr-x  1 oracle dba    188  1月 24 22:46 2
            -rwxr-xr-x  1 oracle dba    188  1月 24 22:46 3
            -rwxr-xr-x  1 oracle dba    188  1月 24 22:46 4
            -rwxr-xr-x  1 oracle dba   2467 2005-02-21  auto
            -rwxr-xr-x  1 oracle dba    182  1月 24 22:46 born___.seen
            -rwxr-xr-x  1 oracle dba    182  1月 24 22:46 born__.seen
            -rwxr-xr-x  1 oracle dba     58  1月 24 22:46 born_.seen
            -rwxr-xr-x  1 oracle dba 463188 2004-10-17  darwin
            -rwxr-xr-x  1 oracle dba 582960  1月 24 22:46 freebsd
            -rwxr-xr-x  1 oracle dba     34  1月 24 22:46 LinkEvents
            -rwxr-xr-x  1 oracle dba 497561 2005-02-21  linux
            -rwxr-xr-x  1 oracle dba      0  1月 25 13:00 mech.levels
            -rwxr-xr-x  1 oracle dba      6  1月 24 22:46 mech.pid
            -rw-r--r--  1 oracle dba      0  1月 25 13:00 mech.session
            -rwxr-xr-x  1 oracle dba   3669  1月 19 13:23 mech.set
            drwxr-xr-x  2 oracle dba   4096  1月 24 22:44 randfiles
            -rwxr-xr-x  1 oracle dba      0  1月 19 13:10 TiGeR02.seen
            -rwxr-xr-x  1 oracle dba      0  1月 19 13:10 TiGeR03.seen
            [root@CCN-BJ-3-578  ]#

            問題原因找到。


            posted @ 2012-05-11 14:15 多彩人生 閱讀(814) | 評論 (0)編輯 收藏

            ctags

            安裝ctags

            sudo apt-get install ctags 

            -------------------------------------------------------------------------------

            生成某項目的tags文件

            cd 項目目錄

            ctags –R    // "-R"表示遞歸創建,也就包括源代碼根目錄下的所有子目錄下的源程序。

            "tags"文件中包括這些對象的列表:
            l 用#define定義的宏
            l 枚舉型變量的值
            l 函數的定義、原型和聲明
            l 名字空間(namespace)
            l 類型定義(typedefs)
            l 變量(包括定義和聲明)
            l 類(class)、結構(struct)、枚舉類型(enum)和聯合(union)
            l 類、結構和聯合中成員變量或函數
            ******注意:運行vim的時候,必須在"tags"文件所在的目錄下運行。否則,運行vim的時候還要用":set tags="命令設定tags文件的路徑,
            這樣vim才能找到"tags"文件 :set tags=/home/xxxxx/tags 在vim中輸入命令導入tags文件

            -------------------------------------------------------------------------------------

            使用三種定位方法

            1) 用命令行。在運行vim的時候加上"-t"參數,例如: [/home/brimmer/src]$ vim -t foo_bar 這個命令將打開定義"foo_bar"(變量或函數或其它) 的文件,并把光標定位到這一行。

            2) 在vim編輯器內用":ta"命令,例如: :ta foo_bar

            3) 最方便的方法是把光標移到變量名或函數名上,然后按下"Ctrl-]"。用"Ctrl-t"退回原來的地方

            posted @ 2012-05-10 20:38 多彩人生 閱讀(586) | 評論 (0)編輯 收藏

            16個桌面Linux用戶必須要知道的Shell命令

            16個桌面Linux用戶必須要知道的Shell命令

            94人收藏此文章, 我要收藏 發表于昨天(13:19) , 已有3773次閱讀 共10個評論
                有些人仍然會有這中愚蠢的想法,他們認為使用Linux就必須使用Linux shell命令。胡說!你可以不懂得任何Linux命令,比如說ps,grep,ls等,但是你仍然可以使用很多現代的Linux桌面發行版。
                Linux的系統管理員與桌面用戶不一樣,他們不像桌面用戶一樣使用Cinnamon, GNOME, Unity, 或者 KDE,他們所有的時間都是用Linux命令。

                對于桌面用戶來講,若是了解一部分Linux命令,你可以更好的使用Linux,體驗它的魅力,下面列舉出了一些:

            Shell 基礎:

                你可以通過打開Linux的terminal(終端)來執行Shell命令。Shell的種類有很多種,例如CSH,Bourne Shell,Korn Shell。在現在的大多數Linux發行版中,默認的Shell一般都是Bourne again shell(bash).

            想看看你的Shell是哪一種,執行下面的命令

            1 echo $SHELL
            在Linux中,$符號代表一個shell 變量。所有的shell都用這種方式使用變量。有一些shell變量在你的系統啟動的時候就有了默認值。例如,$SHELL;$LOGNAME是你的登錄名,而$PATH變量指明了你的shell命令的搜索范圍。
            echo命令的作用就是打印出你的輸入。如果你的輸入具有shell的特殊意義,例如shell變量,他就輸出變量的值。

             

            Echo.png

                一個重要的地方是,你要注意文本的大小寫。例如,ls,是DOS的dir命令的Linux版本。這個命令列出當前工作目錄下的文件列表。如果你輸入的是LS,你得到的只能是“找不到命令”的錯誤信息。
                另外在Linux shell命令中一個重要的地方是,你可以將命令串起來。這是Unix/Linux從第一天開始就有的巧妙的特點。最簡單的將命令連起來的辦法就是使用“|”,我們稱之為“pipe”。第一個命令的輸出就是下一個命令的輸入。
            Linux命令有自己的語法規則:
            基本的語法就像這樣:
            1 command -option file
            例如:
            這行命令的意義是輸出當前目錄的所有文件的文件名,l代表“long”,a代表“all”,有了l選項,你會發現,輸出的內容比較豐富,不只包括文件名,還有文件的訪問權限,所有者,所屬組等。你會發現這個命令會在屏幕上輸出大量的信息,如果當前目錄的文件比較多的話。
            現在就是“pipe”出場的時候了。
            1 ls -la | more

            你會在屏幕上看到如下信息:

            ls-la.png

                你也可以在大多數Linux命令中使用通配符。通配符就是可以代表文件名中任何未知的字符或字符串。例如,*就代表任意字符串,?代表單個字符。例如:
            1 ls -l a*
            這個命令會列出在當前工作目錄下所有的以小寫a開頭的文件,比如說abc.txt,alpha.jpg等等。
            1 ls a?cd

                這條命令會列出所有以小寫a開頭隔一個未知字符以小寫cd結尾的所有文件。例如adcd,axcd,但是不會列出adfdcd,也不會列出axcd.txt。

            一些常用的命令

            man:如果你想了解每一個命令代表什么含義以及他的用法,你就可以使用man(意義為manual)命令,例如:
                man輸出的內容是為系統管理員和開發者編寫的,如果你想了解更多命令的用法,你可以去找網絡上的Linux命令文檔,有一個非常方便的就是丹尼爾·巴雷特的Linux的袖珍指南。
            在以前如果你真的想學習Linux和Unix你必須閱讀man手冊。而在2012年的今天,面對如此好用的圖形界面,這句話顯得不是那么的重要,但是如果你想了解Linux更深,閱讀man手冊仍然是一個好的開始。
            su 和sudo: su命令的作用是切換用戶,這也被稱為超級用戶,因為在有些系統中su命令可以使你以系統的所有權限用戶root登錄。除非你是系統管理員,否則我絕不推薦你使用su切換到root,因為這可能給你帶來很多麻煩。
            一個相對安全的多的辦法是使用sudo命令,這個命令可以上你以root權限運行一個命令。
            這兩個命令都需要系統密碼。在大多數Linux的桌面發行版中這兩個是相同的,就是你系統的第一個用戶設置的密碼。
            grep:grep是一種強大的文本搜索工具,它能使用正則表達式搜索文本,并把匹配的行打印出來。 例如:
            1 grep foo /etc/passwd
            返回在password文件中所有的含有foo的行
            1 grep -i "foo" /etc/passwd
            -i選項是忽略大小寫,這就意味著若某一行含有FOO或FOo也會被搜索到。
            grep還支持遞歸搜索:
            1 grep -r "foo" /home/sjvn
            這條命令將會搜索/home/sjvn目錄及其子目錄下所有的包含“foo”的行
            grep也通常與其他命令串連起來使用,例如:
            1 ls -la | grep foo*
            列出當前目錄下任何以foo開頭的文件或目錄。例如如下文件將被匹配:foo,foobar,foolish.txt等等。
            ps:報告進程的狀態。此命令將顯示哪些程序正在運行。我使用PS和grep比其他任何命令使用的都要多。 
            現在假如你有一個程序運行出了錯誤,你不能再桌面上把他關掉,(我看準你了,火狐),我運行如下命令就能查看他的進程id:
            1 ps -ef | grep firefox
            這條命令做了如下事情:
            1 kill -9 1234
            ·第一,他找出所有當前在我的電腦上運行的程序
            ·然后grep命令找出這些文件中叫“firefox”的,顯示到屏幕上。
            ·每一行都有一個進程id數字。有了,現在我就可以是用...
            kill:這條命令就想他的名字一樣,他可以干掉指定的進程。干掉運行錯誤的firefox或者其他我想干掉的進程。
            1 kill 1234
            這將會干掉所有進程id為1234的程序。為了確保這個程序已經被干掉(強行終止),我使用下面的命令

            clear:  如果你覺得你的屏幕上有太多的東西,看起來很討厭,可以使用clear命令清空。

            文件/目錄命令

            cp:cp代表copy,就是復制,他可以復制一個或多個文件到指定的一個或多個目錄下。
            一個通常的用法是:
            1 cp fred.txt ethel.txt
            把fred.txt中的內容復制到當前文件夾中名為ethel.txt中
            1 cp fred.txt /home/sjvn/docs/fred.txt
            把fred.txt復制到指定文件中。
            1 cp *.txt  /home/sjvn/docs/
            復制當前目錄下所有以.txt結尾的文件到指定的目錄下。
            1 cp -r /home/sjvn/docs/* /home/sjvn/backup
            遞歸的復制在/home/sjvn/docs/目錄下的所有文件到指定的文件夾。
            hostname: 顯示你當前登錄進去的計算機的名稱。
            mv:mv(意義為move)顧名思義就是移動,可以移動指定文件到指定位置。當然這個命令有的時候還可以用來實現重命名。
            例如:
            1 mv fred.txt ethel.txt
            這條命令的作用你可以簡單的認為是重命名fred.txt為ethel.txt。
            當然此命令還有其他用法,此處不再一一羅列,用法與cp類似,只是這條命令不再保留原文件。
            rm:rm代表remove,是刪除的意思,所以我運行:
            1 rm fred.txt
            我將刪除fred.txt。
            我強烈推薦你在執行rm命令的時候使用-i選項。這兒選項將在你執行命令的時候詢問你是否要真的刪除文件。就像這樣:
            1 rm -i fred.txt

            系統信息

            uname: uname -a命令用一行簡短的給你總結的電腦的基本信息。這通常包括你的電腦名稱,Linux內核版本,你的發行版名稱等。

            uname-a.png

            對于更詳細的信息,你可以使用cat命令,他可以顯示你的Linux電腦中的文本信息。
            1 cat /proc/cpuinfo
             展示你的CPU的重要的統計。
            1 cat /proc/version
            展示你的當前運行的Linux發行版的詳細信息。
            1 cat /etc/printcap
             展示你當前安裝的打印機。
            1 set | more: set|more
            組合命令可以給你更多的呢當前的桌面環境變量的信息。單如果你只是想知道你系統環境變量中的某一個或兩個,可以執行如下命令:
            1 echo $PATH

            結束或者說是另一個開始

               這里給你展示的只不過是Linux命令的表皮。成百上千的書和網站可以給你更多更復雜的如何使用Linux命令的展示。本文只是讓你在想了解比Linux Gui更深一層時的參考。

            如果你想學習更多的關于LInux,推薦你去LinuxCommand.org或者看一看Linux in a Nutshell。如果你想變成一個Linux shell編程的大事,推薦你去學習卡梅倫紐漢姆的 Learning the bash Shell 。

            posted @ 2012-05-07 10:36 多彩人生 閱讀(404) | 評論 (0)編輯 收藏

            一個linux 博客

            http://blog.chinaunix.net/uid/20754793/frmd/14822/page/1.html

            posted @ 2012-05-07 09:56 多彩人生 閱讀(305) | 評論 (0)編輯 收藏

            Linux中時間度量

            Linux中時間度量

            一)ANSI clock函數


            1)概述:
            clock 函數的返回值類型是clock_t,它除以CLOCKS_PER_SEC來得出時間,一般用兩次clock函數來計算進程自身運行的時間.

            ANSI clock有三個問題:
            1)如果超過一個小時,將要導致溢出.
            2)函數clock沒有考慮CPU被子進程使用的情況.
            3)也不能區分用戶空間和內核空間.

            所以clock函數在linux系統上變得沒有意義.

            2)測試
            編寫test1.c程序,測試采用clock函數的輸出與time程序的區別.

            vi test1.c
            #include <stdio.h>
            #include <stdlib.h>
            #include <time.h>

            int main( void )
            {
               long i=1000L;
               clock_t start, finish;
               double  duration;
               printf( "Time to do %ld empty loops is ", i );
               start = clock();
               while (--i){
                system("cd");
               }
               finish = clock();
               duration = (double)(finish - start) / CLOCKS_PER_SEC;
               printf( "%f seconds\n", duration );
               return 0;
            }

            gcc test1.c -o test1

            time ./test1
            Time to do 1000 empty loops is 0.180000 seconds

            real    0m3.492s
            user    0m0.512s
            sys     0m2.972s

            3)總結:
            (1)程序調用 system("cd");,這里主要是系統模式子進程的消耗,test1程序不能體現這一點.
            (2)0.180000 seconds秒的消耗是兩次clock()函數調用除以CLOCKS_PER_SEC.
            (3)clock()函數返回值是一個相對時間,而不是絕對時間.
            (4)CLOCKS_PER_SEC是系統定義的宏,由GNU標準庫定義為1000000.

             


            二)times()時間函數

            1)概述:

            原型如下:
            clock_t times(struct tms *buf);

            tms結構體如下:
            strace tms{
             clock_t tms_utime;
             clock_t tms_stime;
             clock_t tms_cutime;
             clock_t tms_cstime;
            }

            注釋:
            tms_utime記錄的是進程執行用戶代碼的時間.
            tms_stime記錄的是進程執行內核代碼的時間.
            tms_cutime記錄的是子進程執行用戶代碼的時間.
            tms_cstime記錄的是子進程執行內核代碼的時間.


            2)測試:

            vi test2.c
            #include <sys/times.h>
            #include <stdio.h>
            #include <stdlib.h>
            #include <sys/types.h>
            #include <unistd.h>

            static void do_cmd(char *);
            static void pr_times(clock_t, struct tms *, struct tms *);

            int main(int argc, char *argv[]){
                    int i;
                    for(i=1; argv[i]!=NULL; i++){
                            do_cmd(argv[i]);
                    }
                    exit(1);
            }
            static void do_cmd(char *cmd){
                    struct tms tmsstart, tmsend;
                    clock_t start, end;
                    int status;
                    if((start=times(&tmsstart))== -1)
                            puts("times error");
                    if((status=system(cmd))<0)
                            puts("system error");
                    if((end=times(&tmsend))== -1)
                            puts("times error");
                    pr_times(end-start, &tmsstart, &tmsend);
                    exit(0);
            }
            static void pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend){
                    static long clktck=0;
                    if(0 == clktck)
                            if((clktck=sysconf(_SC_CLK_TCK))<0)
                                       puts("sysconf err");
                    printf("real:%7.2f\n", real/(double)clktck);
                    printf("user-cpu:%7.2f\n", (tmsend->tms_utime - tmsstart->tms_utime)/(double)clktck);
                    printf("system-cpu:%7.2f\n", (tmsend->tms_stime - tmsstart->tms_stime)/(double)clktck);
                    printf("child-user-cpu:%7.2f\n", (tmsend->tms_cutime - tmsstart->tms_cutime)/(double)clktck);
                    printf("child-system-cpu:%7.2f\n", (tmsend->tms_cstime - tmsstart->tms_cstime)/(double)clktck);
            }

            編譯:
            gcc test2.c -o test2

            測試這個程序:
            time ./test2 "dd if=/dev/zero f=/dev/null bs=1M count=10000"
            10000+0 records in
            10000+0 records out
            10485760000 bytes (10 GB) copied, 4.93028 s, 2.1 GB/s
            real:   4.94
            user-cpu:   0.00
            system-cpu:   0.00
            child-user-cpu:   0.01
            child-system-cpu:   4.82

            real    0m4.943s
            user    0m0.016s
            sys     0m4.828s


            3)總結:
            (1)通過這個測試,系統的time程序與test2程序輸出基本一致了.
            (2)(double)clktck是通過clktck=sysconf(_SC_CLK_TCK)來取的,也就是要得到user-cpu所占用的時間, 就要用
            (tmsend->tms_utime - tmsstart->tms_utime)/(double)clktck);
            (3)clock_t times(struct tms *buf);返回值是過去一段時間內時鐘嘀嗒的次數.
            (4)times()函數返回值也是一個相對時間.

             

            三)實時函數clock_gettime

            在POSIX1003.1中增添了這個函數,它的原型如下:
            int clock_gettime(clockid_t clk_id, struct timespec *tp);

            它有以下的特點:
            1)它也有一個時間結構體:timespec ,timespec計算時間次數的單位是十億分之一秒.
            strace timespec{
             time_t tv_sec;
             long tv_nsec;
            }

            2)clockid_t是確定哪個時鐘類型.

            CLOCK_REALTIME: 標準POSIX實時時鐘
            CLOCK_MONOTONIC: POSIX時鐘,以恒定速率運行;不會復位和調整,它的取值和CLOCK_REALTIME是一樣的.
            CLOCK_PROCESS_CPUTIME_ID和CLOCK_THREAD_CPUTIME_ID是CPU中的硬件計時器中實現的.


            3)測試:
            #include<time.h>
            #include<stdio.h>
            #include<stdlib.h>

            #define MILLION 1000000


            int main(void)
            {
                    long int loop = 1000;
                    struct timespec tpstart;
                    struct timespec tpend;
                    long timedif;

                    clock_gettime(CLOCK_MONOTONIC, &tpstart);

                    while (--loop){
                            system("cd");
                    }

                    clock_gettime(CLOCK_MONOTONIC, &tpend);
                    timedif = MILLION*(tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_nsec-tpstart.tv_nsec)/1000;
                    fprintf(stdout, "it took %ld microseconds\n", timedif);

                    return 0;
            }

            編譯:
            gcc test3.c -lrt -o test3

            計算時間:
            time ./test3
            it took 3463843 microseconds

            real    0m3.467s
            user    0m0.512s
            sys     0m2.936s

             


            四)時間函數gettimeofday()

            1)概述:
            gettimeofday()可以獲得當前系統的時間,是一個絕對值

            原型如下:
            int gettimeofday ( struct timeval * tv , struct timezone * tz )

            timeval結型體的原型如下:
            struct timeval {
                           time_t      tv_sec;    
                           suseconds_t tv_usec;   
                       };

            所以它可以精確到微秒


            測試:
            #include <sys/time.h>
            #include <stdio.h>
            #include <unistd.h>
            int
            main(){
                    int i=10000000;
                    struct timeval tvs,tve;
                    gettimeofday(&tvs,NULL);
                    while (--i);
                    gettimeofday(&tve,NULL);
                    double span = tve.tv_sec-tvs.tv_sec + (tve.tv_usec-tvs.tv_usec)/1000000.0;
                    printf("time: %.12f\n",span);
                    return 0;
            }

            gcc test5.c
            ./a.out
            time: 0.041239000000

             

            五)四種時間函數的比較

            1)精確度比較:

            以下是各種精確度的類型轉換:
            1秒=1000毫秒(ms), 1毫秒=1/1000秒(s);
            1秒=1000000 微秒(μs), 1微秒=1/1000000秒(s);
            1秒=1000000000 納秒(ns),1納秒=1/1000000000秒(s);


            2)
            clock()函數的精確度是10毫秒(ms)
            times()函數的精確度是10毫秒(ms)
            gettimofday()函數的精確度是微秒(μs)
            clock_gettime()函數的計量單位為十億分之一,也就是納秒(ns)


            3)測試4種函數的精確度:

            vi test4.c


            #include    <stdio.h>
            #include    <stdlib.h>
            #include    <unistd.h>
            #include    <time.h>
            #include    <sys/times.h>
            #include    <sys/time.h>
            #define WAIT for(i=0;i<298765432;i++);
            #define MILLION    1000000
                int
            main ( int argc, char *argv[] )
            {
                int i;
                long ttt;
                clock_t s,e;
                struct tms aaa;



                s=clock();
                WAIT;
                e=clock();
                printf("clock time : %.12f\n",(e-s)/(double)CLOCKS_PER_SEC);


                long tps = sysconf(_SC_CLK_TCK);
                s=times(&aaa);
                WAIT;
                e=times(&aaa);
                printf("times time : %.12f\n",(e-s)/(double)tps);


                struct timeval tvs,tve;
                gettimeofday(&tvs,NULL);
                WAIT;
                gettimeofday(&tve,NULL);
                double span = tve.tv_sec-tvs.tv_sec + (tve.tv_usec-tvs.tv_usec)/1000000.0;
                printf("gettimeofday time: %.12f\n",span);


                struct timespec tpstart;
                struct timespec tpend;

                clock_gettime(CLOCK_REALTIME, &tpstart);
                WAIT;
                clock_gettime(CLOCK_REALTIME, &tpend);
                double timedif = (tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_nsec-tpstart.tv_nsec)/1000000000.0;
                printf("clock_gettime time: %.12f\n", timedif);

                return EXIT_SUCCESS;
            }

            gcc -lrt test4.c -o test4
            debian:/tmp# ./test4
            clock time : 1.190000000000
            times time : 1.180000000000
            gettimeofday time: 1.186477000000
            clock_gettime time: 1.179271718000

             

            六)內核時鐘

            默認的Linux時鐘周期是100HZ,而現在最新的內核時鐘周期默認為250HZ.
            如何得到內核的時鐘周期呢?
            grep ^CONFIG_HZ /boot/config-2.6.26-1-xen-amd64

            CONFIG_HZ_250=y
            CONFIG_HZ=250

            結果就是250HZ.

            而用sysconf(_SC_CLK_TCK);得到的卻是100HZ
            例如:

            #include    <stdio.h>
            #include    <stdlib.h>
            #include    <unistd.h>
            #include    <time.h>
            #include    <sys/times.h>
            #include    <sys/time.h>

            int
            main ( int argc, char *argv[] )
            {

                long tps = sysconf(_SC_CLK_TCK);
                printf("%ld\n", tps);
               
                return EXIT_SUCCESS;
            }

            為什么得到的是不同的值呢?
            因為sysconf(_SC_CLK_TCK)和CONFIG_HZ所代表的意義是不同的.
            sysconf(_SC_CLK_TCK)是GNU標準庫的clock_t頻率.
            它的定義位置在:/usr/include/asm/param.h

            例如:
            #ifndef HZ
            #define HZ 100
            #endif

            最后總結一下內核時間:
            內核的標準時間是jiffy,一個jiffy就是一個內部時鐘周期,而內部時鐘周期是由250HZ的頻率所產生中的,也就是一個時鐘滴答,間隔時間是4毫 秒(ms).

            也就是說:
            1個jiffy=1個內部時鐘周期=250HZ=1個時鐘滴答=4毫秒

            每經過一個時鐘滴答就會調用一次時鐘中斷處理程序,處理程序用jiffy來累計時鐘滴答數,每發生一次時鐘中斷就增1.
            而每個中斷之后,系統通過調度程序跟據時間片選擇是否要進程繼續運行,或讓進程進入就緒狀態.

            最后需要說明的是每個操作系統的時鐘滴答頻率都是不一樣的,LINUX可以選擇(100,250,1000)HZ,而DOS的頻率是55HZ.

             

            七)為應用程序計時

            用time程序可以監視任何命令或腳本占用CPU的情況.

            1)bash內置命令time
            例如:
            time sleep 1

            real    0m1.016s
            user    0m0.000s
            sys     0m0.004s


            2)/usr/bin/time的一般命令行
            例如:
            \time sleep 1
            0.00user 0.00system 0:01.01elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
            0inputs+0outputs (1major+176minor)pagefaults 0swaps

            注:
            在命令前加上斜杠可以繞過內部命令.
            /usr/bin/time還可以加上-v看到更具體的輸出:
            \time -v sleep 1
                    Command being timed: "sleep 1"
                    User time (seconds): 0.00
                    System time (seconds): 0.00
                    Percent of CPU this job got: 0%
                    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.00
                    Average shared text size (kbytes): 0
                    Average unshared data size (kbytes): 0
                    Average stack size (kbytes): 0
                    Average total size (kbytes): 0
                    Maximum resident set size (kbytes): 0
                    Average resident set size (kbytes): 0
                    Major (requiring I/O) page faults: 0
                    Minor (reclaiming a frame) page faults: 178
                    Voluntary context switches: 2
                    Involuntary context switches: 0
                    Swaps: 0
                    File system inputs: 0
                    File system outputs: 0
                    Socket messages sent: 0
                    Socket messages received: 0
                    Signals delivered: 0
                    Page size (bytes): 4096
                    Exit status: 0
                   
            這里的輸出更多來源于結構體rusage.

            最后,我們看到real time大于user time和sys time的總和,這說明進程不是在系統調用中阻塞,就是得不到運行的機會.
            而sleep()的運用,也說明了這一點

            posted @ 2012-05-07 09:51 多彩人生 閱讀(1575) | 評論 (0)編輯 收藏

            僅列出標題
            共25頁: First 14 15 16 17 18 19 20 21 22 Last 

            導航

            統計

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久婷婷综合中文字幕| 亚洲欧美伊人久久综合一区二区| 久久无码国产专区精品| 26uuu久久五月天| 77777亚洲午夜久久多喷| 久久久久久久91精品免费观看| 久久精品国产精品亚洲艾草网美妙| 久久精品国产亚洲综合色| 久久91精品国产91久久小草| 97久久精品无码一区二区天美| 久久精品中文闷骚内射| 久久精品国产清高在天天线| 国内精品伊人久久久久AV影院| 久久精品国产亚洲AV忘忧草18| 波多野结衣久久精品| 国产毛片欧美毛片久久久| 精品久久久无码21p发布| 久久精品a亚洲国产v高清不卡| 久久亚洲国产欧洲精品一| 色综合久久中文综合网| 久久久91人妻无码精品蜜桃HD| 欧美性大战久久久久久| 亚洲AV无码久久精品成人| 狠狠色丁香婷综合久久| 久久精品国产亚洲7777| 狠狠色丁香婷婷久久综合| 久久人爽人人爽人人片AV | 精品国产一区二区三区久久久狼| 亚洲日本va中文字幕久久| 国产亚洲美女精品久久久久狼| 久久精品18| 男女久久久国产一区二区三区| 成人国内精品久久久久一区| 久久99精品久久久久久水蜜桃 | 久久免费高清视频| 久久笫一福利免费导航 | 国内精品免费久久影院| 无码国内精品久久人妻| 狠狠色丁香婷婷综合久久来来去| 久久综合久久综合亚洲| 国产69精品久久久久99|