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

C/C++で独自のsizeof演算子を自作する方法|#defineマクロとポインタ演算の活用

独自のsizeof()演算子とは?

C言語やC++では、標準のsizeof()演算子に頼らず、自分専用のsizeof()演算子を自作することも可能です。sizeof()は単項演算子の一種で、変数やデータ型がメモリ上で占めるサイズ(バイト数)を計算するために使われます。#defineディレクティブ(関数形式マクロ)を利用すれば、標準のsizeof()とまったく同じように動作する独自のsizeof()を実装できます。

実装の仕組み

このテクニックの鍵となるのはポインタ演算です。あるオブジェクトのアドレスに1を加えると、ポインタは「その型1つ分」だけ前進します。そこで、元のアドレスと1つ先のアドレスをそれぞれ(char *)にキャストして差を取れば、その差は必ずバイト単位になります。これによってオブジェクトのサイズを求められます。

基本構文

#define Any_name(object) (char *)(&object+1) - (char *)(&object)

各要素の意味は以下の通りです。

  • Any_name: 自分で自由に付けられるマクロ名(独自sizeofの名前)
  • &object: 対象オブジェクトの先頭アドレス
  • &object + 1: 同じ型の「次」のオブジェクトがあると仮定した位置のアドレス(型のサイズぶん進む)
  • (char *)へのキャスト: ポインタの減算を1バイト単位で行うために必須

サンプルプログラム(C言語)

#include <stdio.h>
#define to_find_size(object) (char *)(&object+1) - (char *)(&object)
int main() {
    int x;
    char a[50];
    printf("Integer size : %d\n", to_find_size(x));
    printf("Character size : %d\n", to_find_size(a));
    return 0;
}

実行結果

Integer size : 4
Character size : 50

コードの解説

上記のプログラムでは、#defineディレクティブによって独自のsizeof()であるto_find_sizeを定義しています。このマクロを使うことで、int型変数xのサイズ(4バイト)と、要素数50のchar型配列aのサイズ(50バイト)が正しく計算できています。

特に配列の場合、&a + 1は「配列全体1個分」だけアドレスを進めるため、配列の総バイト数(ここでは50バイト)がそのまま得られる点がポイントです。

注意点

  • マクロは型安全ではないため、誤った使い方をしてもコンパイラが検出してくれない場合があります。
  • 関数の引数として渡された配列はポインタへ退化するため、そのポインタにこのマクロを適用しても期待どおりの結果にはなりません。
  • 実務では、標準のsizeof演算子や、C++17以降であればstd::sizeなどを使用する方が安全です。

このように、ポインタ演算の仕組みを理解すれば、sizeof()と同等の動作をする独自の演算子(マクロ)を実装できます。C/C++の低レベルなメモリ操作を学ぶのに最適な題材と言えるでしょう。

  1. C++でsizeof()が演算子として実装されている理由とは?

    実は、sizeofはC++における本来の意味での演算子ではありません。それは、引数のサイズに等しい値を挿入するための特殊な構文にすぎません。sizeofは実行時のサポートを必要とせず、プログラムの実行中に何らかの処理を行うこともありません。さらに、sizeofはオーバーロードすることもできません。その理由は、配列内のポインタをインクリメントするといった組み込みの基本操作が、暗黙的にsizeofの結果に依存しているためです。もしsizeofをオーバーロードできてしまうと、これらの言語の根幹に関わる動作の一貫性が損なわれてしまいます。C標準におけるsizeofの扱いC言語の標準規格では、sizeo

  2. C++のsizeof演算子とは?基本構文と使い方を実例付きで解説

    sizeof はC++のキーワードであると同時に、コンパイル時に評価される演算子でもあります。変数やデータ型が必要とするメモリのサイズをバイト単位で取得するために使用され、プログラムの実行時ではなくコンパイルの時点でその値が確定する点が特徴です。sizeof演算子は、int や double などの組み込み型だけでなく、クラス・構造体・共用体などユーザー定義のデータ型に対しても使用できます。sizeofの基本構文sizeof (data type)「data type」の部分には、サイズを調べたいデータ型や変数名を指定します。例えば、char 型のオブジェクトに適用した場合は必ず 1 を返しま