変数からデータをダンプするツールを開発しています。変数名と値をダンプする必要があります。
私の解決策:変数名を文字列として保存し、「変数名」の後にその値を出力します。
変数名を知るためのプログラム的な方法はありますか?
変数からデータをダンプするツールを開発しています。変数名と値をダンプする必要があります。
私の解決策:変数名を文字列として保存し、「変数名」の後にその値を出力します。
変数名を知るためのプログラム的な方法はありますか?
次のようなことを試すことができます:
#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname);
私が書いたこのヘッダーを使用していましたが、C を初めて使用したときに、いくつかの有用なアイデアが含まれている可能性があります。たとえば、これにより、C 値を出力し、フォーマット指定子を 1 つ (およびいくつかの追加情報) で提供できます。
#define TRACE(fmt, var) \
(error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var))
C++ を使用している場合は、渡された値の型を使用して適切に出力できます。この場合、変数値を「きれいに印刷」する方法について、はるかに有利な例を提供できます。
C では、変数名はコンパイル ステップ (および変数がグローバルの場合はリンク ステップ) で存在しますが、実行時には使用できません。変数名を示すリテラル文字列を含むソリューションを選択する必要があります。
より短い方法:
#define GET_VARIABLE_NAME(Variable) (#Variable)
テスト:
#include <string>
class MyClass {};
int main(int argc, char* argv[]) {
int foo = 0;
std::string var_name1 = GET_VARIABLE_NAME(foo);
char* var_name2 = GET_VARIABLE_NAME(foo);
char* var_name3 = GET_VARIABLE_NAME(MyClass);
return 0;
}
私は実際にあなたが望むことをするかもしれないいくつかのコードを持っています。プリプロセッサを使用して変数名を文字列化し、印刷できるようにします。変数の名前と値(タイプに基づく)とその変数のメモリレイアウトの両方をダンプします。次のプログラムは、それがどのように行われるかを示しています。
#include <stdio.h>
#include <stdlib.h>
static void dumpMem (unsigned char *p, unsigned int s) {
int i;
unsigned char c[0x10];
printf (">> ");
for (i = 0; i < 0x10; i++) printf (" +%x",i);
printf (" +");
for (i = 0; i < 0x10; i++) printf ("%x",i);
printf ("\n");
for (i = 0; i < ((s + 15) & 0xfff0); i++) {
if ((i % 0x10) == 0) {
if (i != 0) printf (" %*.*s\n", 0x10, 0x10, c);
printf (">> %04x ",i);
}
if (i < s) {
printf (" %02x", p[i]);
c[i & 0xf] = ((p[i] < 0x20) || (p[i] > 0x7e)) ? '.' : p[i];
} else {
printf (" ");
c[i & 0xf] = ' ';
}
}
printf (" %*.*s\n", 0x10, 0x10, c);
}
#define DUMPINT(x) do{printf("%s: %d\n",#x,x);dumpMem((char*)(&x),sizeof(int));}while(0)
#define DUMPSTR(x) do{printf("%s: %s\n",#x,x);dumpMem(x,strlen(x));}while(0)
#define DUMPMEM(x,s) do{printf("%s:\n",#x);dumpMem((char*)(&x),s);}while(0)
typedef struct {
char c;
int i;
char c2[6];
} tStruct;
int main (void) {
int i = 42;
char *s = "Hello there, my name is Pax!";
tStruct z;
z.c = 'a'; z.i = 42; strcpy (z.c2,"Hello");
DUMPINT (i);
DUMPSTR (s);
DUMPMEM (z,sizeof(z));
return 0;
}
これは以下を出力します:
i: 42
>> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000 2a 00 00 00 *...
s: Hello there, my name is Pax!
>> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000 48 65 6c 6c 6f 20 74 68 65 72 65 2c 20 6d 79 20 Hello there, my
>> 0010 6e 61 6d 65 20 69 73 20 50 61 78 21 name is Pax!
z:
>> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000 61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61 a..a*...Hello..a
また、マクロの健全性について疑問がある場合は、do {...} while (0)
周囲に十分な中括弧があるかどうかを気にすることなく、コード内のどこにでも配置できるようにする必要があります。
任意の変数に対してこれを行う必要がある場合は、コンパイラまたはプラットフォームが提供するデバッガAPI(WindowsのDbgHelpなど)を使用する必要があります。
私が取り組んだいくつかの組み込みシステムでは、事前にわかっている特定の重要な変数の値をコマンドで表示できるようにする必要がありました。そのために必要なのは、単純な名前/ポインターテーブルだけです。
typedef
struct vartab {
char const* name;
int * var;
} vartab;
vartab varTable[] = {
{ "foo", &foo },
{ "bar", &bar }
};
次に、問題の変数名をテーブルで検索し、名前とポインターが指すデータをダンプする小さなルーチンを使用しました。プレーンint以外のデータをダンプする必要がある場合は、構造を拡張してprintfスタイルのフォーマッターも保持し、ポインターをaに変更して、void*
そのジャンクをsnprintf()
データのフォーマットなどに渡すことができます。
テーブルの作成に役立つマクロを使用することもあります(場合によっては変数を宣言することもできます)。しかし、正直なところ、それは理解を本当に複雑にし(特に、プロジェクトに新しく参加した人にとっては、小さな「WTF?」の瞬間があることが多い)、物事をそれほど単純化しないと思います。
人々はしばしば、プログラムが自己内省する (または現在の専門用語で「反映する」) ことを望んでいます。しかし、ほとんどのプログラミング言語は、プログラムのすべての詳細 (変数名、関数名、型、式の構造など) を反映する機能をほとんど提供しないか (Java など)、まったく提供しません (C)。
すべての言語でこれを行う方法があります。言語の外に出て、言語からその情報を抽出するように設計されたツールを使用します。これを行うことができるツールのクラスは、プログラム変換システムと呼ばれます。
プログラム変換システムを使用して「変数名を取得」し、値を出力する方法の説明については、この SO の回答を参照してください: 変数への変更を自動的に追跡する
これを試して。
#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable)
コード (void) 変数は何もしない void 変換であり、カンマ演算子とマクロ stringify があります。したがって、最終的な結果は、変数名を含む const char* であり、コンパイラ チェックでは変数が実際に存在します。
これで変数の名前がわかり、printf() を使用してその値を出力できます。
実行可能ファイルがデバッグ情報でコンパイルされている場合、この情報を取得できる可能性があります。そうでない場合は、おそらく運が悪いです。では、デバッガを構築していますか? なんで?c 用の既存のデバッガーは非常に成熟しています。車輪を再発明するのではなく、既存のツールを使用してみませんか?
プログラム内からそれを行う良い方法はありません。残念ながら(Anacrolixの回答は別として)。あなたの問題に対する正しい解決策は、デバッガー スクリプトだと思います。ほとんどのデバッガーでは、デバッガーがプログラムの実行を中断するたびに実行するように接続することもできます (ブレークポイント、ヒット^C
など)、対話するたびにプログラムの状態のスナップショットを取得できます。