WGC1 第3章2進数の算術演算子とビット演算 3.6 ビットフィールドとデータのパック その2

2桁のみの日付形式というのは、2000年問題など、配慮に欠けているデータ形式
そのため、年を0〜65535とし、32bitのデータ形式を使用する。

x86のunsigned intのイメージ

31 16 15 8 7 0
> > > > > > > > > > > > > > > 年(0〜65535) > > > > > > > 月(1〜12) > > > > > > 日(1〜31)

この日付方式では、年の範囲を除いた2バイト分に月と日の各フィールドにそれぞれ1バイトを割り当てている。
余分な領域はあるが、1バイトのフィールドなら、アプリケーションでは、バイトオブジェクトとして簡便に操作できるので
バイトアクセスをサポートするプロセッサにおいては、フィールドのパック、アンパックに要するオーバーヘッドを軽減できる。
32bit=4バイト使用するのなら、short,char,charでもサイズは変わらない。
この形式の目的は、サイズの削減ではなく、パックすることで、パッケージ化されているカプセル化されているということ。
データをダブルワード変数(unsigned intのイメージ)にパックすることにより、3つの別変数ではなく、単一のデータ値として扱える。
その場合、このデータに対する操作は3つの個別の命令ではなく、単一の命令で済む。
また、この形式では、符号なし整数の比較により、日付を簡単に比較できる。~
高水準言語の中には、パックされたデータのサポートが標準で組み込まれているものがある。
C言語では、次のような構造体を定義できる。

struct {
    unsigned bits0_3      :4;
    unsigned bits4_11     :8;
    unsigned bits12_15    :4;
    unsigned bits16_23    :8;
    unsigned bits24_31    :8;
}packed_data;

C/C++コンパイラが32bitのダブルワードの値をこれらの各フィールドを
どのように割り当ててるかは、コンパイラ依存。ビット列の中のビットの
配置もコンパイラ依存。
ビットフィールド宣言を使用する場合は、移植性はないと考えてまず間違いない

実験コード

#include 
#include 

struct {
    unsigned bits0_3      :4;
    unsigned bits4_11     :8;
    unsigned bits12_15    :4;
    unsigned bits16_23    :8;
    unsigned bits24_31    :8;
}packed_data;

struct {
    unsigned year   :7;
    unsigned month  :4;
    unsigned day    :5;
} short_date;

int main(int argc, char* argv[]){
    
    packed_data.bits0_3   = 0xF;
    packed_data.bits4_11  = 0xFF;
    packed_data.bits12_15 = 0x0;
    packed_data.bits16_23 = 0xAA;
    packed_data.bits24_31 = 0x55;
    
    printf("each filed = %#x, %#x, %#x, %#x, %#x\n", 
            packed_data.bits0_3,
            packed_data.bits4_11,
            packed_data.bits12_15,
            packed_data.bits16_23,
            packed_data.bits24_31
          );
    printf("data filed = %#x\n",    packed_data);
    
    short_date.year = 9;  /* 2009 */
    short_date.month = 1;
    short_date.day = 31;
    
    printf("The short date is %02d/%02d/%02d (year/month/day), size is %d\n",
            short_date.year,
            short_date.month,
            short_date.day,
            sizeof(short_date));
            
    return 1;
    
}

環境

コンパイル

[oc@centos5 3.6bitfield_and_datapack]$ gcc packeddata.c -o packeddata

結果

[oc@centos5 3.6bitfield_and_datapack]$ ./packeddata
each filed = 0xf, 0xff, 0, 0xaa, 0x55
data filed = 0x55aa0fff
The short date is 09/01/31 (year/month/day), size is 4

環境

コンパイル

D:\workspace\C_SandBox\10BOOKs\WGC1\3.6bitfield_and_datapack>cl packeddata.c
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

packeddata.c
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:packeddata.exe
packeddata.obj

結果

D:\workspace\C_SandBox\10BOOKs\WGC1\3.6bitfield_and_datapack>packeddata
each filed = 0xf, 0xff, 0, 0xaa, 0x55
data filed = 0x55aa0fff
The short date is 09/01/31 (year/month/day), size is 4


Windows x86Linux 86は同じだった。
32bit変数だから、エンディアンと同じになってるっぽいな。

SPARC SolarisLinux x64、Windows x64、の環境でも試してみたい。









Randall Hyde、鵜飼 文敏、まつもと ゆきひろ、後藤 正徳、トップスタジオ