Cでコンパイル時にsizeof()の結果を印刷するにはどうすればよいですか?
今のところ、静的アサート(他のWebリソースに基づいて作成されたホーム)を使用して、sizeof()の結果をさまざまな定数と比較しています。これは機能しますが、エレガントでも高速でもありません。変数/構造体のインスタンスを作成してマップファイルを調べることもできますが、これは直接呼び出し/コマンド/演算子よりもエレガントで高速でもありません。さらに、これは複数のクロスコンパイラを使用した組み込みプロジェクトです...そのため、サンプルプログラムをビルドしてターゲットにロードし、値を読み出すことは、上記のいずれよりもさらに面倒です。
私の場合(古いGCC)、#warning sizeof(MyStruct)
は実際に警告を出力する前にsizeof()を解釈しません。
私がこれにつまずいたとき、私は同様の機能を探してあざけっていました:
コンパイル時に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をもう少しよく知っている人は、虐待に対するより良い警告を考えることができます。
必要なのは、重複した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
もう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固有です。他のすべての方法は私にとってはうまくいきませんでした。
GCC、Clang、MSVCなどで動作する次の方法は、古いバージョンでも、ポインターから配列への関数パラメーターの変換の失敗に基づいています)スカラー型へ。コンパイラーは配列のサイズを出力するため、出力から値を取得できます。 CモードとC++モードの両方で機能します。
sizeof(long)
を見つけるためのコード例( オンラインでプレイ ):
_char checker(int);
char checkSizeOfInt[sizeof(long)]={checker(&checkSizeOfInt)};
_
関連する出力の例:
<source>:1: note: expected 'int' but argument is of type 'char (*)[8]'
<source>:1:6: note: candidate function not viable: no known conversion from 'char (*)[8]' to 'int' for 1st argument;
<source>(2): warning C4047: 'function': 'int' differs in levels of indirection from 'char (*)[4]'
私の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です。
ええと...それはオプションです。
@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]"
私は Bakhazard の great solution に似た解決策に出くわしましたが、これはあまり冗長な警告を生成しないので、あなたはそれを役に立つと思うかもしれません:
_char (*__fail)(void)[sizeof(uint64_t)] = 1;
_
これはエラーメッセージを生成します
_Function cannot return array type 'char [8]'
_
これは、clang(1)
の最新バージョンでテストされました。
これは正確にはコンパイル時ではありませんが、実行前に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