unionで混在する型で正しく動作するには?

解決


TM  2006-10-24 05:27:37  No: 63392

下のソースでTESTUNIONが2バイトなぜか増え
格納データもおかしいです。これはunionの仕様でしょうか?
環境はWindows 2000,Visual C++ 6.0です。
よろしくお願いします。

以下ソースです。

#include<iostream>
#include<iomanip>

using namespace std;
namespace {
    union NI{
        char aa[6];
        struct ST{
            unsigned short ST1;
            int  ST2;
        }TESTSTRUCT;
    }TESTUNION;

    union NI2{
        char aa[6];
        struct ST{
            unsigned short ST1;
            unsigned short ST2;
            unsigned short ST3;
        }TESTSTRUCT;
    }TESTUNION2;
}
int main(){
    int i;

    char buff[8]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
    for (i=0;i<=6;i++){
    TESTUNION.aa[i]=buff[i];
    TESTUNION2.aa[i]=buff[i];
    }
      
    
    cout << "TESTUNIONのサイズ:" << sizeof(TESTUNION) << endl;
    cout << "TESTUNION.aaのサイズ:" << sizeof(TESTUNION.aa) << endl;
    cout << "TESTUNION.TESTSTRUCTのサイズ:" << sizeof(TESTUNION.TESTSTRUCT) << endl;
    cout << "TESTUNION.TESTSTRUCT.ST1のサイズ:" << sizeof(TESTUNION.TESTSTRUCT.ST1) << endl;
    cout << "TESTUNION.TESTSTRUCT.ST2のサイズ:" << sizeof(TESTUNION.TESTSTRUCT.ST2) << endl;
    cout << uppercase << setbase(16) << "TESTUNION.TESTSTRUCT.ST1の中身:" << TESTUNION.TESTSTRUCT.ST1 << endl;
    cout << uppercase << setbase(16) << "TESTUNION.TESTSTRUCT.ST2の中身:" << TESTUNION.TESTSTRUCT.ST2 << endl;
    cout << "↑全体が2バイト増え、ST1の最後から2バイト分、飛ばしている。なぜ????" << endl;
    cout << "次のunionはうまくいく" << endl;
    cout << "-------------------------------------------" << endl;    
    cout << "TESTUNION2のサイズ:" << sizeof(TESTUNION2) << endl;
    cout << "TESTUNION2.aaのサイズ:" << sizeof(TESTUNION2.aa) << endl;
    cout << "TESTUNION2.TESTSTRUCTのサイズ:" << sizeof(TESTUNION2.TESTSTRUCT) << endl;
    cout << "TESTUNION2.TESTSTRUCT.ST1のサイズ:" << sizeof(TESTUNION2.TESTSTRUCT.ST1) << endl;
    cout << "TESTUNION2.TESTSTRUCT.ST2のサイズ:" << sizeof(TESTUNION2.TESTSTRUCT.ST2) << endl;
    cout << "TESTUNION2.TESTSTRUCT.ST3のサイズ:" << sizeof(TESTUNION2.TESTSTRUCT.ST3) << endl;
    cout << uppercase << setbase(16) << "TESTUNION2.TESTSTRUCT.ST1の中身:" << TESTUNION2.TESTSTRUCT.ST1 << endl;
    cout << uppercase << setbase(16) << "TESTUNION2.TESTSTRUCT.ST2の中身:" << TESTUNION2.TESTSTRUCT.ST2 << endl;
    cout << uppercase << setbase(16) << "TESTUNION2.TESTSTRUCT.ST3の中身:" << TESTUNION2.TESTSTRUCT.ST3 << endl;
    
    return 0;
}
/* 
実行結果

TESTUNIONのサイズ:8
TESTUNION.aaのサイズ:6
TESTUNION.TESTSTRUCTのサイズ:8
TESTUNION.TESTSTRUCT.ST1のサイズ:2
TESTUNION.TESTSTRUCT.ST2のサイズ:4
TESTUNION.TESTSTRUCT.ST1の中身:2211
TESTUNION.TESTSTRUCT.ST2の中身:776655
↑全体が2バイト増え、ST1の最後から2バイト分、飛ばしている。なぜ????
次のunionはうまくいく
-------------------------------------------
TESTUNION2のサイズ:6
TESTUNION2.aaのサイズ:6
TESTUNION2.TESTSTRUCTのサイズ:6
TESTUNION2.TESTSTRUCT.ST1のサイズ:2
TESTUNION2.TESTSTRUCT.ST2のサイズ:2
TESTUNION2.TESTSTRUCT.ST3のサイズ:2
TESTUNION2.TESTSTRUCT.ST1の中身:2211
TESTUNION2.TESTSTRUCT.ST2の中身:4433
TESTUNION2.TESTSTRUCT.ST3の中身:6655
*/


yoh2  2006-10-24 06:41:04  No: 63393

>        struct ST{
>             unsigned short ST1;
>             int  ST2;
>         }TESTSTRUCT;

ST2を4バイト境界に揃えるために、ST1とST2の間に2バイトのパディングが入っているのでしょう。

こんな感じ。
    0   1   2   3   4   5   6   7   (パイト)   
    [ ST1  ][ PAD  ][     ST2      ]

cout << offsetof(NI::ST, ST2) << '&#92;n';

としてみて4が出力されればパディング入り決定。(#include <cstddef> をお忘れなく)
でもって、TESTUNION.aaのデータが一部パディング領域と重なるから2バイト分飛ばされているように見えるわけです。

ところで、

> for (i=0;i<=6;i++){

〜.aaのサイズを1バイトオーバーしていますよ。


TM  2006-10-24 08:06:14  No: 63394

調べてみたのですが、__attribute__ ((packed))でパディングを
抑制できるようですね。

>〜.aaのサイズを1バイトオーバーしていますよ。
すみません、ご指摘ありがとうございました。


yoh2  2006-10-24 08:26:16  No: 63395

えーと、それはgcc用の設定だと思うのですが。
VC6は#pragma packですね。(使い方は適当に検索して下さい)


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加