程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> c語言 union及 大端小端

c語言 union及 大端小端

編輯:關於C

union 關鍵字的用法與struct 的用法非常類似。

union 維護足夠的空間來置放多個數據成員中的“一種”,而不是為每一個數據成員配置空間,在union 中所有的數據成員共用一個空間,同一時間只能儲存其中一個數據成員,所有的數據成員具有相同的起始地址。例子如下:

union StateMachine
{
   char character;
   int number;
   char *str;
   double exp;
};

**一個union 只配置一個足夠大的空間以來容納最大長度的數據成員**

    以上例而言,最大長度是double 型態,所以StateMachine 的空間大小就是double 數據類型的大小。

在C++裡,union 的成員默認屬性頁為public。union 主要用來壓縮空間。

如果一些數據不可能在同一時間同時被用到,則可以使用union。

一、大小端模式對union 類型數據的影響

下面再看一個例子:

union
{
   int i;
   char a[2];
}*p, u;
p =&u;
p->a[0] = 0x39;
p->a[1] = 0x38;

p.i 的值應該為多少呢?

    這裡需要考慮存儲模式:大端模式和小端模式。
  • 大端模式(Big_endian):字數據的高字節存儲在低地址中,而字數據的低字節則存放在高地址中。

    輸出為0x39380000
    
  • 小端模式(Little_endian):字數據的高字節存儲在高地址中,而字數據的低字節則存放在低地址中。

    輸出為0x00003839  
    
    union 型數據所占的空間等於其最大的成員所占的空間。對union 型的成員的存取都是相對於該聯合體基地址的偏移量為0 處開始,也就是聯合體的訪問不論對哪個變量的存取都是從union 的首地址位置開始。如此一解釋,上面的問題是否已經有了答案呢?
    

    二、如何用程序確認當前系統的存儲模式?

    上述問題似乎還比較簡單,那來個有技術含量的:

    • 請寫一個C 函數,若處理器是Big_endian 的,則返回0;若是Little_endian 的,則返回1。

      先分析一下,按照上面關於大小端模式的定義,假設int 類型變量i 被初始化為1。

      • 以大端模式存儲,其內存布局如下圖:

        \

        • 以小端模式存儲,其內存布局如下圖:

          \

          變量i 占4 個字節,但只有一個字節的值為1,另外三個字節的值都為0。如果取出低地址上的值為0,毫無疑問,這是大端模式;如果取出低地址上的值為1,毫無疑問,這是小端模式。既然如此,我們完全可以利用union 類型數據的特點:所有成員的起始地址一致。
          

          到現在,應該知道怎麼寫了吧?參考答案如下:

          int checkSystem( )
          {
             union check
             {
                int i;
                char ch;
             } c;
             c.i = 1;
             return (c.ch ==1);
          }
          

          現在你可以用這個函數來測試你當前系統的存儲模式了。當然你也可以不用函數而直接去查看內存來確定當前系統的存儲模式。如下圖:

          \

          圖中0x01 的值存在低地址上,說明當前系統為小端模式。

          不過要說明的一點是,某些系統可能同時支持這兩種存儲模式,你可以用硬件跳線或在編譯器的選項中設置其存儲模式。

          留個問題:在x86 系統下,輸出的值為多少?<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;">#include intmain() { int a[5]={1,2,3,4,5}; int *ptr1=(int *)(&a+1); int *ptr2=(int *)((int)a+1); printf("%x,%x",ptr1[-1],*ptr2); return 0; }

          解答: 對於*ptr1應該比較容易判斷

          sizeof(a)=20 a[5] 的大小為 4*5=20個字節
          此時內存內容為:

          a                                                        ptr[-1]   &a+1
          01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00        00
          
          

          &a+1 表示一次要加上20個字節 而 ptr1[-1]=往後偏移一個字節 所以ptr[-1]=5

          (int)a +1 跟 &a+1 區別注意 非常大 (int)a+1 表示將a的地址變為整數之後加1,這裡的偏移地址只是邏輯上加了一個單位

          a (int)a+1                                                  &a+1
          01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 00
          
          

          此時*ptr2指向的四個字節為 00 00 00 02由於計算機采用小端模式 將 00 00 00 02強制轉換成 int * 就變成了 02 00 00 00了
          注意: 00 00 00 02這裡的地址依次增大,所以02此時位於高地址

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved