2012-03-09 9 views
1

を理解できないコードは次のとおりです。は、任意のヘルプはここで素晴らしい:)</p> <p>だろう、私はideone.com上のコードのこの部分を試みたが、それは準拠していますが、私は何が起こっているのかを説明することはできません。この組合

#include <stdio.h> 


typedef union { 
    unsigned char*  g_pointer; 
    struct { 
     unsigned short   local_addr; 
     unsigned char   globle_page; 
     } g_l; 
    } Gld_WordType; 


int main() 
{ 
    int Idx; 
    Gld_WordType test; 
    test.g_l.globle_page = 0x13; 
    test.g_l.local_addr = 0xfff0; 

    printf("g_pointer: %x\n 
      local_addr: %x\n 
      globle_page: %x\n", 
      test.g_pointer, 
      test.g_l.local_addr, 
      test.g_l.globle_page); 

    test.g_pointer++;  

    printf("g_pointer: %x\n 
      local_addr: %x\n 
      globle_page: %x\n", 
      test.g_pointer, 
      test.g_l.local_addr, 
      test.g_l.globle_page); 

    return 0; 
} 

結果は次のとおりです。

g_pointer: 13fff0 
local_addr: fff0 
globle_page: 13 
g_pointer: 13fff1 
local_addr: fff1 
globle_page: 13 

そして私は単にlocal_addrgloble_pageの順序を切り替えた場合、結果は切り抜いたことが判明:

結果は
typedef union { 
    unsigned char*  g_pointer; 
    struct { 
     unsigned char   globle_page; // Changed order here. 
     unsigned short   local_addr; // And here 
     } g_l; 
} Gld_WordType; 

この時、:

g_pointer: fff00013 
local_addr: fff0 
globle_page: 13 
g_pointer: fff00014 
local_addr: fff0 
globle_page: 14 

OK、ここではこの問題の私の理解は今まででどんな障害がある場合は、それを指摘してください。 globle_pagelocal_addr前に定義されている場合

1は、組合は

############ ############# 
#   # #   # 
# g_pointer# # local_addr# 
#   # # MSB or LSB# 
############ ############# 
       ############# 
       #   # 
       # local_addr# 
       # MSB or LSB# 
       ############# 
       ############## 
       #   # 
       # globle_page# 
       #   # 
       ############## 

とレイアウト(globle_pageの前のにlocal_addrがある)このようなものである第一の例では、このように構成されている。

############ ############## 
#   # #   # 
# g_pointer# # globle_page# 
#   # #   # 
############ ############## 
       ############## 
       #   # 
       # local_addr # 
       # MSB or LSB # 
       ############## 
       ############## 
       #   # 
       # local_addr # 
       # MSB or LSB # 
       ############## 

ので(globle_page前に定義されてlocal_addr)状況1で、g_pointerの値chages、local_addrのMSBまたはLSBあまりにも変更されます場合は、しかし、なぜ実際にそれを追加していますか?私のプラットフォームがビッグエンディアンのバイトオーダーであることを知っているので、local_addrのMSBを変更する必要があります。なぜLSBが変更されるのですか?

状況2( globle_pagelocal_addr前に定義された)、私は、 g_pointer余りに1を加算の値が1、および `globle_pageの対応するアドレスを追加する"ことを説明することができますではなくので、状況1の

、私はのかなりわからないんだけどこの。

ここで起こっていることの正確な答えを誰にでも教えてもらえますか?質問を適切に記述しなかった場合、私の貧しい人の英語のことをお詫びします。

btw、私が使用しているプラ​​ットフォームはバイト整列の問題がありません。したがって、sturctはバイトごとに書かれたレイアウトです。

よろしく、 盛ユン

+0

問題はどこですか?ユニオンは要件ごとにLSBで整列されているため、一方に '1'を追加すると' 1'が他にも追加されます。構造体のメンバのアライメントは実際には実装固有ですが、コンパイラは明白なことをしました2番目の例の 'unsigned char'は実際に' unsigned char'と1の 'unsigned char'パディングを加えたものです。 – hroptatyr

+2

標準的なリトルエンディアンのように見えます。あなたのプラットフォームは何ですか?ビッグエンディアンであることはどうやって分かりますか? –

+0

@Banthar Doing Embedding Cのプログラミング、宇宙のコンパイラを使用して、使用しているマイクロチップのバイトオーダーがBig-Endianだと言われました – shengy

答えて

1
could anyone tell me the exact answer of what is happening here? 

知って最初の、そして最も重要なことは、結果が未定義の動作であるということです。コンパイラごとに異なる結果が表示される可能性があります。同じコンパイラでも異なるオプションを使用しています。最も一般的な代替動作では、あるフィールドを変更すると、他のフィールドは将来、ある時間まで変更されません。私は、フォーム

// assign to the first field 
// print the second field 
// print the second field 

の過去にいくつかのテストコードを書いていると、最初の印刷は、2番目のフィールドの前の値を示しており、第二の印刷は、2番目のフィールドの更新された値を示しています。

あなた本当には、あなたがこの方法で決して使用union秒はず、あなたはエイリアシングと未定義の動作に関してやっていることを学ぶまで。

次に知っておくべきことは、ポインタがまれに1バイト長であることです。最新のマシンでは、4バイトまたは8バイトの傾向があります。

データレイアウトについて次に知ることは、時にはstructsがパディングされることです。構造体

struct { 
    char a; 
    short b; 
}; 

のために私はレイアウトが

<one byte of a> <unused byte> <two bytes of b> 

<one byte of a> <two bytes of b> 

として、私は

<one byte of a> <3 unused bytes> <two bytes of b> 

を見てunsurprisedだろうであること、それは同じように可能性が高いと思うだろう実際、経験的な結果に基づいて私はあなたが4バイトのポインタを持っていることを期待しています。この最後の可能性はstructが実際にどのようにレイアウトされているかです。

sizeofoffsetofの機能を使用して、正確に物を判断することができます。 sizeofは、それぞれの型の長さが何バイトであるかを示します。offsetofは、構造体または共用体の各フィールドがどこで始まるかを正確に判断できるようにします。

ポインタはではなく、常にのように配置されていることに注意してください。この問題は、実行しているコンピュータのアーキテクチャによって異なります。私はすべての "一般的な"ものはあなたが期待するように行動すると思います。

+0

この問題は未定義の問題なのでしょうか? – shengy

+0

実装定義の動作です。 – hroptatyr

+0

@ shengy:これが最も重要なポイントです。しかし、私はまた、あなたが何を見ているかを説明するための情報を提供していました(特にあなたが分析で間違っていたこと)。実際の実装で見られる最も一般的な振る舞いは、フィールドが期待どおりに変化することですが、*あなたのプログラムが更新された値を取得したときには予測不可能(または準予測可能)です。 – Hurkyl

0

調査するには、メンバーに配置されている場所を確認するためにaxtraフィールドをユニオンに追加します。

typedef union { 
    unsigned char*  g_pointer; 
    struct { 
     unsigned short   local_addr; 
     unsigned char   globle_page; 
     } g_l; 
    unsigned char all[ sizeof (unsigned char*)]; 
    } Gld_WordType; 
関連する問題

 関連する問題