web-dev-qa-db-ja.com

Cでコンパイル時にsizeof()の結果を印刷するにはどうすればよいですか?

Cでコンパイル時にsizeof()の結果を印刷するにはどうすればよいですか?

今のところ、静的アサート(他のWebリソースに基づいて作成されたホーム)を使用して、sizeof()の結果をさまざまな定数と比較しています。これは機能しますが、エレガントでも高速でもありません。変数/構造体のインスタンスを作成してマップファイルを調べることもできますが、これは直接呼び出し/コマンド/演算子よりもエレガントで高速でもありません。さらに、これは複数のクロスコンパイラを使用した組み込みプロジェクトです...そのため、サンプルプログラムをビルドしてターゲットにロードし、値を読み出すことは、上記のいずれよりもさらに面倒です。

私の場合(古いGCC)、#warning sizeof(MyStruct)は実際に警告を出力する前にsizeof()を解釈しません。

41
altendky

私がこれにつまずいたとき、私は同様の機能を探してあざけっていました:

コンパイル時にC++クラスのサイズを出力することは可能ですか?

これは私にこのアイデアを与えました:

char (*__kaboom)[sizeof( YourTypeHere )] = 1;

これにより、VS2015で次の警告が発生します。

warning C4047: 'initializing': 'DWORD (*)[88]' differs in levels of indirection from 'int'

ここで、88は探しているサイズです。

とてもハッキーですが、それはトリックをします。おそらく数年は遅すぎますが、これが誰かに役立つことを願っています。

私はまだgccやclangを試す機会がありませんでしたが、誰かが私の前にアクセスできなかった場合に動作するかどうかを確認しようとします。

編集:clang 3.6ですぐに使用可能

GCCで働くことができる唯一のトリックは、-Wformatおよびマクロに次のような関数を定義させます。

void kaboom_print( void )
{
    printf( "%d", __kaboom );
}

次のような警告が表示されます。

...blah blah blah... argument 2 has type 'char (*)[88]'

元の提案よりも少し粗いですが、gccをもう少しよく知っている人は、虐待に対するより良い警告を考えることができます。

52
Bakhazard

必要なのは、重複したcase定数など、コンパイル時の整数値が誤って使用されていることについてコンパイラーから不平を言うトリックです:

struct X {
    int a,b;
    int c[10];
};
int _tmain(int argc, _TCHAR* argv[])
{
    int dummy;

    switch (dummy) {
    case sizeof(X):
    case sizeof(X):
        break;
    }
    return 0;
}

コンパイル結果:

 ------ Build started: Project: cpptest, Configuration: Debug Win32 ------
 cpptest.cpp c:\work\cpptest\cpptest\cpptest.cpp(29): error C2196: case value '48' already used
 ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

したがって、構造体Xのサイズは48

6
JavaMan

もう1つの方法(実際に機能します):

char __foo[sizeof(MyStruct) + 1] = {[sizeof(MyStruct)] = ""};

古い 'gcc 5.xで動作します。次のようなエラーが生成されます。

a.c:8:54: error: initializer element is not computable at load time
a.c:8:54: note: (near initialization for 'a[8]')

追伸明らかに、これは(非常に)gcc固有です。他のすべての方法は私にとってはうまくいきませんでした。

5

GCC、Clang、MSVCなどで動作する次の方法は、古いバージョンでも、ポインターから配列への関数パラメーターの変換の失敗に基づいています)スカラー型へ。コンパイラーは配列のサイズを出力するため、出力から値を取得できます。 CモードとC++モードの両方で機能します。

sizeof(long)を見つけるためのコード例( オンラインでプレイ ):

_char checker(int);
char checkSizeOfInt[sizeof(long)]={checker(&checkSizeOfInt)};
_

関連する出力の例:

  • GCC 4.4.7

<source>:1: note: expected 'int' but argument is of type 'char (*)[8]'

  • clang 3.0.0

<source>:1:6: note: candidate function not viable: no known conversion from 'char (*)[8]' to 'int' for 1st argument;

  • MSVC 19.14

<source>(2): warning C4047: 'function': 'int' differs in levels of indirection from 'char (*)[4]'

2
Ruslan

私のgcc Cコンパイラは、上記のソリューションのいずれかを使用してサイズを印刷することを拒否します。ロジックを反転させて、サイズに応じてコンパイラー警告を挿入しました。

enum e
{
    X = sizeof(struct mystruct)
};

void foo()
{
    static enum e ev;

    switch (ev)
    {
    case 0:
    case 4:
    case 8:
    case 12:
    case 16:
    case 20:
        break;
    }
}

次に、不足している番号の警告を確認する必要があります。

warning: case value '0' not in enumerated type 'e' [-Wswitch]
warning: case value '4' not in enumerated type 'e' [-Wswitch]
warning: case value '12' not in enumerated type 'e' [-Wswitch]
warning: case value '16' not in enumerated type 'e' [-Wswitch]
warning: case value '20' not in enumerated type 'e' [-Wswitch]

したがって、構造体のサイズは8です。

私の梱包は4です。

ええと...それはオプションです。

0
jws

@jwsいいね!。ただし、sizeof(xxx)は定数式(VLA、 https://en.cppreference.com/w/c/language/sizeof を除く)であるため、sizeof演算子はその場合でも機能するはずです選択:

enum e1 {dummy=-1};
enum e1 ev;
switch (ev) {
    case sizeof(myType):;
    break;
    default:;
}

..それは私のGCCで動作します: "..\WinThreads.c:18:9:警告:列挙型 'enum e1'にないケース値 '4' [-Wswitch]"

0
dsptech

私は Bakhazardgreat solution に似た解決策に出くわしましたが、これはあまり冗長な警告を生成しないので、あなたはそれを役に立つと思うかもしれません:

_char (*__fail)(void)[sizeof(uint64_t)] = 1;
_

これはエラーメッセージを生成します

_Function cannot return array type 'char [8]'
_

これは、clang(1)の最新バージョンでテストされました。

0
EHYPERCHICKEN

これは正確にはコンパイル時ではありませんが、実行前にisであるため、一部の人にとっては関連性があります。

次のように配列を定義できます。

uint8_t __some_distinct_name[sizeof(YourTypeHere)];

そして、コンパイル後、オブジェクトファイルからサイズを取得します。

$ nm -td -S your_object_file |       # list symbols and their sizes, in decimal
  grep ' __some_distinct_name$' |    # select the right one
  cut -d' ' -f2 |                    # grab the size field
  xargs printf "Your type is %d B\n" # print
0
user10746164