Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

【C言語】sizeofとoffsetofで構造体メンバーのサイズとオフセットを表示するプログラムの作成方法

C言語では、sizeof演算子とoffsetofマクロを組み合わせることで、構造体そのもののサイズや、各メンバー変数のサイズ・オフセット(構造体の先頭からのバイト位置)を簡単に調べることができます。本記事では、構造体の基本をおさらいしながら、実際にサイズとオフセットを表示するプログラムまでをわかりやすく解説します。

問題

構造体を定義し、そのメンバー変数のサイズとオフセットを表示するCプログラムを作成しましょう。

構造体(Structure)とは、異なるデータ型の変数を1つの名前のもとにグループ化して扱えるようにした集合体のことです。

構造体宣言の一般形式

datatype member1;
struct tagname{
    datatype member2;
    datatype member n;
};

ここで、structは構造体を定義するためのキーワードです。

tagnameは構造体の名前を指定します。

member1、member2は、構造体を構成する個々のデータ項目を表します。

struct book{
    int pages;
    char author[30];
    float price;
};

構造体変数の宣言方法

構造体変数の宣言には、主に以下の3つの方法があります。

方法1:構造体の定義と同時に宣言する

struct book{
    int pages;
    char author[30];
    float price;
}b;

方法2:タグ名を省略して宣言する

struct{
    int pages;
    char author[30];
    float price;
}b;

方法3:定義後に別途宣言する

struct book{
    int pages;
    char author[30];
    float price;
};
struct book b;

構造体の初期化とアクセス

メンバーと構造体変数を結びつけるには、メンバー演算子(ドット演算子「.」)を使用します。

構造体の初期化は、以下のいずれかの方法で行えます。

方法1:宣言時にまとめて初期化する

struct book{
    int pages;
    char author[30];
    float price;
} b = {100, "balu", 325.75};

方法2:タグ付きの型で宣言して初期化する

struct book{
    int pages;
    char author[30];
    float price;
};
struct book b = {100, "balu", 325.75};

方法3:メンバー演算子を使って個別に代入する

struct book{
    int pages;
    char author[30];
    float price;
};
struct book b;
b.pages = 100;
strcpy(b.author, "balu");
b.price = 325.75;

方法4:scanf関数で入力する

struct book{
    int pages;
    char author[30];
    float price;
};
struct book b;
scanf("%d", &b.pages);
scanf("%s", b.author);
scanf("%f", &b.price);

サイズとオフセットを表示するプログラム

それでは、複数のデータメンバーを持つ構造体を宣言し、各メンバーのオフセット値と構造体全体のサイズを表示してみましょう。

offsetofマクロはstddef.hヘッダーで定義されており、第1引数に構造体型、第2引数にメンバー名を指定すると、構造体の先頭アドレスからそのメンバーまでのバイト数(オフセット)を返します。

#include<stdio.h>
#include<stddef.h>
struct tutorial{
    int a;
    int b;
    char c[4];
    float d;
    double e;
};
int main(){
    struct tutorial t1;
    printf("the size 'a' is :%d\n",sizeof(t1.a));
    printf("the size 'b' is :%d\n",sizeof(t1.b));
    printf("the size 'c' is :%d\n",sizeof(t1.c));
    printf("the size 'd' is :%d\n",sizeof(t1.d));
    printf("the size 'e' is :%d\n",sizeof(t1.e));
    printf("the offset 'a' is :%d\n",offsetof(struct tutorial,a));
    printf("the offset 'b' is :%d\n",offsetof(struct tutorial,b));
    printf("the offset 'c' is :%d\n",offsetof(struct tutorial,c));
    printf("the offset 'd' is :%d\n",offsetof(struct tutorial,d));
    printf("the offset 'e' is :%d\n\n",offsetof(struct tutorial,e));
    printf("size of the structure tutorial is :%d",sizeof(t1));
    return 0;
}

実行結果

the size 'a' is :4
the size 'b' is :4
the size 'c' is :4
the size 'd' is :4
the size 'e' is :8
the offset 'a' is :0
the offset 'b' is :4
the offset 'c' is :8
the offset 'd' is :12
the offset 'e' is :16

size of the structure tutorial is :24

実行結果の解説

出力結果から、int型とfloat型は4バイト、char配列(要素4個)は4バイト、double型は8バイトであることが確認できます。また、オフセットはメンバーの宣言順に「0 → 4 → 8 → 12 → 16」と並んでおり、double型のメンバーeが8バイト境界に正しく配置されていることがわかります。

なお、この例では合計24バイトとなりパディング(詰め物)は発生していませんが、メンバーの並び順によっては、コンパイラがアライメント(整列)のためにパディングを挿入し、構造体のサイズが各メンバーの合計より大きくなる場合があります。sizeofoffsetofを活用すれば、こうしたメモリ配置を実際に確認できるので、メモリ効率を意識した構造体設計にも役立ちます。

  1. 【初心者向け】C言語で二次方程式の根(解)を求めるプログラムの作り方

    問題ソフトウェア開発の手法をC言語に適用し、二次方程式の根(解)を求めるプログラムを作成します。解決策二次方程式 ax2 + bx + c = 0 の根を求めます。二次方程式には必ず2つの根が存在します。分析入力:係数 a、b、c の値出力:根 r1、r2 の値手順(解の公式)二次方程式の根は、以下の「解の公式」によって求めることができます。$r_{1}=\frac{-b+\sqrt{b^2-4ac}}{2a}$$r_{2}=\frac{-b-\sqrt{b^2-4ac}}{2a}$ここで、b2 − 4ac を判別式と呼びます。判別式の値によって、根の性質が次のように変わります。判別式 >

  2. PythonでDataFrameのインデックスと列を転置(入れ替え)する3つの方法

    はじめにpandasのDataFrameでは、行と列を入れ替える「転置(transpose)」操作がよく使われます。本記事では、特定のDataFrameのインデックスと列を転置するための3つの方法を、具体的なコード例とともにわかりやすく解説します。たとえば、次のような元のDataFrameがあるとします。import pandas as pd data = [[1,2,3],[4,5,6]] df = pd.DataFrame(data) print(元のDataFrame:\n, df)出力結果:元のDataFrame: 0 1 2 0 1 2 3 1 4 5 6このDataFrame