Yabu.log

色々勉強するブログです

C言語復習その3構造体、共用体について

構造体と共用体について学びました。

構造体のサイズについて

  • コンパイラが勝手にサイズを偶数長になるように変更する
  • 構造体の正確なサイズはわからない。
    • sizeof演算子で大きさを求めるべき。
      • 実際の現場でもsizeof演算子で大きさを求める場面は結構あるらしい。

Bitフィールド

  • char(1Byte)より小さい長さで構造体のメンバを分割
  • 1bit,2bitの長さの型はないのかと常に疑問だったのでこれは嬉しい。
    • 低レイヤー勢は使いまくってそう。
  • 1Byte以下の長さをもつレジスタの分割なんかはこれを利用するといいんじゃないかなと思いました。
  • 型はint,unsigned int,signed intのみ
  • メンバの長さが中途半端だとアドレスをまたぐことがありえる
    • 名前なしのビットフィールドを活用してワードアライメント的な埋めを開発者が設定できる。
  • bitフィールドのアドレスは参照できない。
    • バイトの単位でアドレスは振られる
      • ビットフィールドはバイトより小さな長さを持ち得るのでアドレスが割り振れない
      • そのメンバの開始地点のアドレスくらいわかってもいいんじゃないかな〜と思った。
typedef struct{
    unsigned al:8;
    unsigned ah:8;
} registers;

・・・

//bitフィールドのメンバのアドレスは参照できない。
//chap2/struct.c:37:30: error: address of bit-field requested
printf("ah adress is %p\n",&registers.ah);
//bitフィールドを使った構造体のアドレスは取得可能。
printf("registers adress is %p\n",&registers);

共用体

  • ある値の何バイト目まで、というような値の参照ができる。
  • 見た瞬間にCPUのレジスタを扱うのに向いているのでは?と思った。
  • hikaliumさんが過去に作られていたOSで適当にunionとググってみたところcpuのレジスタのbitを共用体で表現しているところがありました。

github.com

  • EFLAGSやCRnレジスタはnビット目がこれ!という表現を共用体を使わないと混乱すると思います。
  • Linuxでも共用体でレジスタっぽいものを表現していました。*1
  • たぶんCPUのレジスタを共用体で表現するということは普通に行われていることなのでしょう。
    • 本書ではほとんど使われない、と書かれているが、ある程度低レイヤーの分野の書籍を読んだことがあると用意の活用イメージが湧く。

確かに面白いのですが、実際のところ普通のプログラミングをしている限り、ほとんど用途がありません。ですから、こういうものがある、ということだけ覚えておけば十分でしょう。

  • COBOLに似たような機能があった気がする。レベル変数?とか言った気が。

tallercolibri.com

eaxを共用体で表現

  • eat ax ah alを共用体で作って見ましたが。。。
#include <stdio.h>
typedef struct{
    //unsigned al:8;
    unsigned char al;
    //unsigned ah:8;
    unsigned char ah;

} ax_8bit;

typedef union {
    //unsigned ax:16
    short ax;
    ax_8bit _8bit;
} ax;
typedef union{
    //unsigned eax:32
    int eax;
    ax axpart;
}eax;
}

出力

eax is 0x1d2c65b8
ax  is 0x    65b8
al  is 0x      b8
ah  is 0x    65

eax size is 4
ax  size is 2
ah  size is 1
al  size is 1

eax addr is 0x7ffeec3b9ae0
eax addr is 0x7ffeec3b9ae0
ax  addr is 0x7ffeec3b9ae0
ah  addr is 0x7ffeec3b9ae1
al  addr is 0x7ffeec3b9ae0

0x7ffeec3b9ae0 is b8
0x7ffeec3b9ae1 is 65
0x7ffeec3b9ae2 is 2c
0x7ffeec3b9ae3 is 1d

0x7ffeec3b9ae0をベースアドレスにして整理すると

offset 0 1 2 3
value b8 65 2c 1d
8bit r [al] [ah] - -
16bit r [ax ax] - -
32bit r [eax eax eax eax]

下位アドレス、上位アドレスなどの並びがちょっと混乱してわからない。これあってるのかな?

プログラミング学習シリーズ C言語改訂版 2 はじめて学ぶCの仕組み

プログラミング学習シリーズ C言語改訂版 2 はじめて学ぶCの仕組み

*1:ネットワークのパケット周りでも使われている