トップC-Tips > 構造体スリムプログラム

構造体スリムプログラム

通常のプログラムでは構造体が頻繁に使われる。 このページでは、構造体関連のプログラムのコツについて記す。

1.初期化機能によるスリム化

下にC言語インタプリタの作成で用いた命令を表す構造体INSTRUCTの定義 およびこの構造体配列 Inst[IMAX] にデータをセットするoutInst7関数を示す。

typedef struct _OPERAND { 
    int type, rix, ival; 
} OPERAND;

typedef struct _INSTRUCT { 
    int opcode;
    OPERAND opd1, opd2;
} INSTRUCT;

INSTRUCT *outInst7(int opcode, int t1, int i1, int v1, int t2, int i2, int v2) {
    INSTRUCT *pI = &Inst[nInst++];
    pI->opcode = opcode;
    pI->opd1.type = t1;
    pI->opd1.rix  = i1;
    pI->opd1.ival = v1;
    pI->opd2.type = t2;
    pI->opd2.rix  = i2;
    pI->opd2.ival = v2;
    return pI;
}

outInst7関数は、構造体変数の初期値付き宣言を使えば、次に示すように、極めてシンプルとなる。 memcpy関数の代わりに構造体の代入演算を使う方法もあるが、 例えばTCCの場合、構造体の代入演算は内部的には memcpy関数を用いており、実質は変わらない。 MCCは現バージョンでは構造体の代入演算をサポートしていないが、 前バージョンではやはり memcpy関数で実装していた。

INSTRUCT *outInst7(int opcode, int t1, int i1, int v1, int t2, int i2, int v2) {
    INSTRUCT inst = { opcode, {t1, i1, v1}, {t2, i2, v2} };
    return memcpy(&Inst[nInst++], &inst, sizeof(inst));
}

もう一つの事例を下に示す。

typedef struct _Name {
    int  type;			// NM_VAR: 変数、NM_FUNC: 関数
    char *dataType, *name;	// データ型, 変数名または関数名
    int  addrType, address;	// アドレスの種別, 相対アドレス
} Name;

// 関数または変数情報を名前管理表に登録する
Name *appendName(int nB, int type, char *dataType, char *name, int addrType, int addr) {
    Name *pNew = calloc(1, sizeof(Name));
    if (pNew == NULL) error("appendName: メモリが足りません");
    pNew->type = type;
    pNew->name = name;
    pNew->dataType = dataType;
    pNew->addrType = addrType;
    pNew->address = addr;
    if (nB == 0 && nGlobal < SIZEGLOBAL-1) GlobalName[nGlobal++] = pNew;
    else if (nB == 1 && nLocal < SIZELOCAL-1) LocalName[nLocal++] = pNew;
    else error("appendName: 引数エラーまたは配列オーバーフロー");
    return pNew;	// 新しいエントリのアドレスを返す
}
Name *appendName(int nB, int type, char *dataType, char *name, int addrType, int addr) {
    Name *pNew = calloc(1, sizeof(Name));
    if (pNew == NULL) error("appendName: メモリが足りません");
    Name nm = { type, dataType, name, addrType, addr };
    memcpy(pNew, &nm, sizeof(Name)); 
    if (nB == 0 && nGlobal < SIZEGLOBAL-1) GlobalName[nGlobal++] = pNew;
    else if (nB == 1 && nLocal < SIZELOCAL-1) LocalName[nLocal++] = pNew;
    else error("appendName: 引数エラーまたは配列オーバーフロー");
    return pNew;	// 新しいエントリのアドレスを返す
}

この方法は構造体の要素数が多いときに特に効果が大きい。