青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Thronds

一問你會什么 二問你做出過什么 三問你為了什么

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  36 隨筆 :: 0 文章 :: 56 評論 :: 0 Trackbacks
    在求職筆試中,C中的位域是一個??键c,特別是在嵌入式軟件中更常見。位域的最大好處是可以根據自己需要定制位數,從而節省空間,例如:嵌入式編程稀缺的內存資源。還有在網絡通訊中,對頭信息部分的結構定義也常用到位域,少傳一位是一位啊。
    這里來分析EMC的一道筆試題(07年招聘試題):
1 typedef struct bitstruct 2 { 3 int b1:5; 4 int :2; 5 int b2:2; 6 }bitstruct; 7 int main(int argc, char *argv[]) 8 { 9 bitstruct b; 10 printf("%d\n",sizeof(bitstruct)); 11 memcpy(&b,"EMC Examination",sizeof(b)); 12 printf("%d,%d\n",b.b1,b.b2); 13 return 0; 14 }
請問在little-endian systems(系統默認的存放順序)中,輸出結果是什么?
答案是
4 
5-2;

所需知識點:
1.位域的概念和特點
    C語言允許在一個結構體中以位為單位來指定其成員所占內存長度,這種以位為單位的成員稱為“位段”或稱“位域”(bit field)。(1)位段成員的類型必須指定為unsigned或int類型;(2)若某一位段要從另一個字開始存放,用:0長度為0的空位段,作用就是使下一個位段從下一個存儲單位(視不同編譯系統而異)開始存放;(3)一個位段必須存儲在同一存儲單元中,不能跨兩個單元;(4)可以定義無名字段例如":2";(5)位段的長度不能大于存儲單元的長度,也不能定義位段數組;(6)位段可以用整形格式符輸出;(7)位段可以在數值表達式中引用,它會被系統自動地轉換成整形數。[1][3]

2.Little-endian systems的內存布局特點
   
    先問一個問題:Endian這個詞是什么意思?

    “endian”這個詞出自《格列佛游記》。小人國的內戰就源于吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發生過六次叛亂,其中一個皇帝送了命,另一個丟了王位。

    我們一般將endian翻譯成“字節序”,將big endian和little endian稱作“大尾”和“小尾”。這也在當今的CPU派別中一樣存在。Motorola的PowerPC系列CPU采用的Big-endian, Intel的X86系列CPU采用的是Little-endian。Little-endian的特點是高高低低,即高位地址存放最高有效字節,低位地址存放最低有效字節;而Big-endian正好相反。下面用圖的方式說明起來更直觀,例如0x12345678(特別注意,這是單個數,不是字符串,如果是字符串就不一定這樣了。之前沒有特別注意這點,害的我多花了冤枉時間)。
Big Endian

   低地址                                            高地址
   ----------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     12     |      34    |     56      |     78    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian

   低地址                                            高地址
   ----------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     78     |      56    |     34      |     12    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    上面的字節序的不同,在單機的操作中沒有問題,因為一臺單機就是采用單一的字節序嘛!但是在兩個不同的主機進行協作時,就會出現問題了;另外在網絡通訊中也同樣會出現問題,詳細參考[2]

就單個字節而言,也會有這樣的問題:比特序有差別嗎?

    也分成兩種序,如果我們處理的基本單位是字節以上的話,對此就不必擔心了,因為CPU存儲操作的最小單元是字節,所以比特位的順序對我們來就是透明的,我們在讀取某個字節時,不管它用的是Big endian 還是Little endian,我們讀到的都是一個同樣的字節,只不過硬件在讀寫時的順序,一個是從高到底另一個是從低到高,對我們的使用不產生影響。但是如果涉及到位域的存放問題,還是要特別小心,上面這道題就是一個非常的好的例子。

Big Endian

   msb                                                         lsb
   ---------------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   1  |   0  |   1  |   1  |   0  |   1  |   0  |   0  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian

   lsb                                                         msb
   ---------------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   0  |   0  |   1  |   0  |   1  |   1  |   0  |   1  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


3.memcpy()與strcpy()的區別
    這個問題很簡單,可以想象成這樣:memcpy的基本單位是位,strcpy的基本單位是字符。所以,memcpy會根據提供的長度完全按位拷貝,而strcpy是兩個字符串之間的拷貝。

    回來原來的問題上,在采用little endian的BUS64中,struct bitstruct在沒涉及到高低位問題時,也就是我們平時常會畫出的一種形式是:
{b1 b1 b1 b1 b1 Ø Ø b2   b2 Ø Ø Ø Ø Ø Ø Ø    ØØØØØØØØ   ØØØØØØØØ};
在內存中的實際布局是:

   低地址                                                 高地址
   -------------------------
------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+
   | b2 Ø Ø b1 b1 b1 b1 b1 |Ø Ø Ø Ø Ø Ø Ø b2 |ØØØØØØØØ |ØØØØØØØØ |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+

Ø表示空填充,這當中包含一個原則:一個位域的存放不可以跨字存放,但可以跨字節存儲;這里采用的比特續也是little endian,說明了比特序對操作也是有影響的嘛!

    memcpy按位拷貝“EMC Examination”到b中,一個字符是8位; 又因為sizeof(b)=4,所以只寫入"EMC "。"EMC "對應的位序列是:{0100 0101  0100 1101  0100 0011  0010 0000},從這里寫到內存里的形式是:(在這里不要被little endian給迷惑了,E不是放在高地址,參看上面紅色的特別注意

   低地址                                                 高地址
   -------------------------
------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+
   | b2 Ø Ø b1 b1 b1 b1 b1 |Ø Ø Ø Ø Ø Ø Ø b2 |ØØØØØØØØ |ØØØØØØØØ |
   | 0  1 0 0  0  1 0  1 |0  1  0  0 1  1 0  1 |0100 0011     |0010 0000    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

printf("%d,%d\n",b.b1,b.b2);讀出來的b1是00101,它的值是5; b2是10,轉換成十進制是-2。


到了這一步,似乎題目已經解答出來了,但還有兩個地方有疑惑:
1.struct bitstruct在內存中的位存放順序是這樣的么?
   低地址                                                 高地址
   -------------------------
------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+
   | b2 Ø Ø b1 b1 b1 b1 b1 |Ø Ø Ø Ø Ø Ø Ø b2 |ØØØØØØØØ |ØØØØØØØØ |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.memcpy函數在按位拷貝時的拷貝順序是這樣的么?
   低地址                                                 高地址
   -------------------------
------------------------------------->
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+
   | 01000101 | 01001101 |0100 0011 |0010 0000 |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
關于上面兩個問題的驗證工作留給路過的朋友來做:-P .....  歡迎批評指正

[1]譚浩強 C程序設計 第二版 清華大學出版社
[2]http://blog.csdn.net/sunshine1314/archive/2008/04/20/2309655.aspx
[3]http://topic.csdn.net/t/20061207/10/5212742.html#
[4]http://elanso.com/ArticleModule/LmT3M6M6HGKzTDQcPKMGKAIi.html
[5]關于字節序與編碼的關聯請參考http://elanso.com/ArticleModule/LmT3M6M6HGKzTDQcPKMGKAIi.html
posted on 2008-12-06 16:17 thronds 閱讀(6334) 評論(9)  編輯 收藏 引用 所屬分類: C++技術 、面試題

評論

# re: C中的位域 2009-12-08 22:54 haohaoking
哥們,你這文章寫得,還是刪除了吧~  回復  更多評論
  

# re: C中的位域 2010-06-20 00:20 bobluo
寫得很好,圖文并茂,但是有點問題。
你的結果是對的,但是內存布局反了:
實際的內存布局:
低地址 高地址
-------------------------------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| b1 b1 b1 b1 b1 Ø Ø b2 | b2 Ø Ø Ø Ø Ø Ø Ø |ØØØØØØØØ |ØØØØØØØØ |
| 1 0 1 0 0 0 1 0 |1 0 1 1 0 0 1 0 |11000010|00000100|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

1)b1對應的內存內容為
(低地址)--------->(高地址)
101000
在little-endian里面比特序的低地址的bit是低有效位,高地址的bit是高有效位,因此對應的數值要反過來看,為0x000101,即5
2)b2對應的內存內容為
(低地址)--------->(高地址)
01
同樣,對應的數值為0x10,即-2。

當然,你這樣的話ascii碼都是從左向右讀(低地址在左),比較符合人的習慣,但是little-endian的話,ascii碼在內存中的實際布局正好相反。而位域無論大小端序,都是從低地址到高地址依次存放的,不會出現你說的這種b2的兩位相隔如此之遠的情況,這和位域本身的目的背道而馳
  回復  更多評論
  

# re: C中的位域 2010-06-20 00:29 bobluo
另外有個錯誤,你專門用紅色標出來的特別注意是錯的,strcpy和memcpy的結果是一樣的,不存在你所說的差別。都是按字節拷貝,而且字節在內存中的比特序受大小端序的影響。而非你說的不要受小端序迷惑。如果是大端序,那么是
低地址 高地址
-------------------------------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| b1 b1 b1 b1 b1 Ø Ø b2 |b2 Ø Ø Ø Ø Ø Ø Ø |ØØØØØØØØ |ØØØØØØØØ |
| 0 1 0 0 0 1 0 1 |0 1 0 0 1 1 0 1 |0100 0011|0010 0000|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  回復  更多評論
  

# re: C中的位域 2010-11-25 10:26 newmalloc
其實,這個問題不用搞得那么復雜;
每個bit在內存中的分布順序,在拷貝的時候由Memcpy來負責對齊,我們要弄清的是b1的5 bits是字節的低位開始分布的,那么只需要知道E的asic是0x45,找到最低5位,即00101b,即可知道b1=5;b2也是同樣的道理  回復  更多評論
  

# re: C中的位域 2011-09-08 12:41 digdeep126
#include <stdio.h>
struct mystr_t {
unsigned short f1:12;
unsigned short f2: 4;
};
int main()
{
struct mystr_t st;
unsigned char *pst;

st.f1 = 0xFFF;
st.f2 = 0x9;

pst = (unsigned char *)&st;
printf("%x %x\n", pst[0], pst[1]);

return 0;
}
結果顯示為:
FF 9F

按照你們的理解,請解釋這里的結果(gcc編譯運行)。

原因是:
編譯器調整了 struct mystr_t。編譯將f2放到前面去了,而f1放到了后面。還有由于cpu是小端序。

所以說,位域在內存中的存放,要看情況,并不是一定是“在little-endian里面比特序的低地址的bit是低有效位,高地址的bit是高有效位”!  回復  更多評論
  

# re: C中的位域 2012-09-21 18:26 拉拉
@bobluo
這哥們別隨便說別人不對,根據我的機器驗證,樓主說的內存布局是很正確的。  回復  更多評論
  

# re: C中的位域 2012-09-21 18:31 拉拉
@digdeep126
真正的原因是:內存布局為(第一字節)f1 f1 f1 f1 f1 f1 f1 f1,(第二字節)f2 f2 f2 f2 f1 f1 f1 f1, 按字節取當然就是 ff 9f 啦  回復  更多評論
  

# re: C中的位域 2012-09-21 18:32 拉拉
但是這里的 -2 是怎會回事?求指教,為什么一定是負的?  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品久久久久久久9999| 一区二区三区四区国产| 亚洲高清一区二区三区| 性色av一区二区三区红粉影视| 影音先锋欧美精品| 国产一区二区精品久久91| 欧美午夜国产| 国产一区二区三区精品欧美日韩一区二区三区 | 美女爽到呻吟久久久久| 在线亚洲观看| 亚洲一区免费看| 久久久久久久性| 欧美精品日本| 国产日韩精品一区| 亚洲国产日韩欧美在线图片| 日韩一区二区精品在线观看| 99视频超级精品| 久久伊人亚洲| 亚洲视频在线视频| 午夜在线精品| 美女精品国产| 亚洲午夜av在线| 欧美成人一区在线| 国产日韩欧美综合一区| 亚洲激情自拍| 久久综合久久综合九色| 亚洲靠逼com| 欧美 日韩 国产一区二区在线视频| 欧美日韩亚洲91| 最近中文字幕日韩精品 | 一本色道久久综合亚洲精品不| 亚洲视频axxx| 亚洲茄子视频| 老牛国产精品一区的观看方式| 欧美无砖砖区免费| 99香蕉国产精品偷在线观看| 欧美激情中文字幕在线| 鲁大师影院一区二区三区| 亚洲高清视频一区| 亚洲第一黄色| 欧美日韩视频第一区| 亚洲性视频网址| 亚洲自拍三区| 亚洲大片免费看| 亚洲美女精品久久| 国产精品一区二区视频| 免费人成精品欧美精品| 另类尿喷潮videofree| 亚洲在线视频观看| 久久成人精品无人区| 国产色婷婷国产综合在线理论片a| 欧美日韩国产另类不卡| 亚洲欧美日本伦理| 午夜免费电影一区在线观看| 136国产福利精品导航网址应用| 最新成人av网站| 国产午夜精品视频| 日韩五码在线| 91久久精品一区| 午夜精品视频网站| 亚洲视频福利| 欧美高清在线观看| 欧美成人高清视频| 在线观看成人av| 午夜欧美大尺度福利影院在线看| 亚洲国产欧美在线| 欧美一级二级三级蜜桃| 亚洲一区二区精品在线| 免费在线亚洲欧美| 亚洲国产一二三| 亚洲国产欧美在线人成| 久久久久久伊人| 乱码第一页成人| 亚洲国产精品一区二区三区| 久久九九热re6这里有精品| 美国十次了思思久久精品导航| 国产欧美日韩另类视频免费观看| 亚洲欧美国产毛片在线| 欧美怡红院视频| 影音先锋中文字幕一区| 免费人成精品欧美精品| 欧美大片在线观看一区二区| 激情综合亚洲| 欧美日韩国产精品一区二区亚洲 | 久久综合导航| 亚洲日本免费| 国产精品美女一区二区在线观看 | 亚洲肉体裸体xxxx137| 欧美黄色大片网站| 亚洲宅男天堂在线观看无病毒| 久久av在线看| 999亚洲国产精| 国产区亚洲区欧美区| 欧美在线免费| 欧美在线免费观看| 欧美激情黄色片| 久久av免费一区| 欧美1区3d| 午夜一区二区三区不卡视频| 亚洲韩日在线| 国产精品自拍网站| 亚洲国产精品va在线观看黑人| 亚洲欧美日韩天堂| 国产一区二区丝袜高跟鞋图片| 亚洲大胆视频| 国产欧美日韩精品丝袜高跟鞋| 久久九九精品| 国产亚洲一级| 午夜性色一区二区三区免费视频| 亚洲图色在线| 午夜国产精品影院在线观看| 亚洲高清一二三区| 这里只有精品电影| 欧美18av| 久色婷婷小香蕉久久| 欧美呦呦网站| 亚洲免费一级电影| 99视频一区| 亚洲另类自拍| 在线性视频日韩欧美| 日韩系列在线| 亚洲欧美三级伦理| 日韩一级黄色片| 亚洲制服欧美中文字幕中文字幕| 日韩亚洲欧美综合| 久久久久久久欧美精品| 欧美裸体一区二区三区| 亚洲丁香婷深爱综合| 久久精品国产综合精品| 欧美激情第五页| 欧美亚洲一区三区| 久久乐国产精品| 亚洲国产三级网| 亚洲卡通欧美制服中文| 欧美在线观看网站| 欧美激情中文字幕乱码免费| 韩国福利一区| 99香蕉国产精品偷在线观看| 欧美在线亚洲| 亚洲激情在线视频| 欧美怡红院视频| 久久精品国产久精国产一老狼| 久久国产精品亚洲77777| 一本一本久久a久久精品综合妖精| 日韩视频免费观看高清完整版| 亚洲男人的天堂在线aⅴ视频| 蜜臀av性久久久久蜜臀aⅴ| 国产亚洲一区二区精品| 亚洲一区二区网站| 亚洲人成人一区二区在线观看| 亚洲先锋成人| 久久综合伊人| 国产一区二区主播在线| 一区二区三区不卡视频在线观看 | 久久一二三四| 亚洲精品黄色| 亚洲综合视频一区| 亚洲国产一区二区三区高清| 久久国产天堂福利天堂| 亚洲美女av黄| 另类天堂av| 亚洲一区久久久| 亚洲小视频在线观看| 国产精品v亚洲精品v日韩精品 | 国产精品毛片a∨一区二区三区| 黑人巨大精品欧美黑白配亚洲| 久久精品国产99国产精品澳门| 亚洲综合电影一区二区三区| 国产欧美精品va在线观看| 欧美在线啊v| 欧美日韩国产在线一区| 亚洲欧美经典视频| 欧美成人久久| 欧美日韩一区二区精品| 亚洲精品视频免费观看| 一区二区三区欧美成人| 亚洲成人在线网| 亚洲看片网站| 91久久精品久久国产性色也91| 久久高清福利视频| 久久精品国产99国产精品| 国产尤物精品| 久久乐国产精品| 国产精品成人av性教育| 久久精品99国产精品酒店日本| 蜜臀av国产精品久久久久| 亚洲自拍16p| 欧美 日韩 国产精品免费观看| 久久国产精品99精品国产| 欧美日韩一区二区三区免费| 久久综合一区二区| 国产欧美一区二区三区在线老狼| 99re热这里只有精品免费视频| 亚洲国产精品久久久久秋霞蜜臀| 亚洲伊人一本大道中文字幕| 欧美一级二级三级蜜桃| 国产亚洲永久域名| 亚洲蜜桃精久久久久久久| 宅男精品导航| 欧美激情在线狂野欧美精品|