web-dev-qa-db-ja.com

Cで変数名を取得するプログラム的な方法は?

変数からデータをダンプするツールを開発しています。変数名と値もダンプする必要があります。

私の解決策:変数名を文字列として保存し、「変数名」の後にその値を出力します。

変数名を知るためのプログラム的な方法はありますか?

31
Alphaneo

あなたはこのようなことを試すことができます:

#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname);

以前は this header を使用していましたが、Cを初めて使用したときに、いくつかの便利なアイデアが含まれている可能性があります。たとえば、これによりCの値を出力し、1つの形式指定子(およびいくつかの追加情報)を提供できます。

#define TRACE(fmt, var) \
        (error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var))

C++を使用している場合は、渡された値のタイプを使用して、適切に出力できます。これが事実である場合、変数値を「きれいに出力」する方法について、はるかに有利な例を提​​供できます。

51
Matt Joiner

Cでは、変数名はコンパイルステップ(および変数がグローバルの場合はリンクステップ)中に存在しますが、実行時には使用できません。変数名を示すリテラル文字列を含むソリューションを選択する必要があります。

11
Greg Hewgill

私は実際にあなたが望むことをするかもしれないいくつかのコードを持っています。プリプロセッサを使用して変数名を文字列化し、出力できるようにします。変数名と値(タイプに基づく)とその変数のメモリレイアウトの両方をダンプします。次のプログラムは、その方法を示しています。

_#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)の健全性について疑問に思っている場合は、それをコード内のどこにでも配置できるようにすることで、中括弧が十分にあるかどうかを気にする必要がありません。

6
paxdiablo

より短い方法:

#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;
}
5
SaeidMo7

任意の変数に対してこれを行う必要がある場合は、コンパイラまたはプラットフォームが提供するデバッガAPI(WindowsのDbgHelpなど)を使用する必要があるでしょう。

一部の組み込みシステムでは、事前にわかっている特定の重要な変数の値をコマンドで表示できるようにする必要があり、必要なことは単純な名前/ポインターテーブルだけです。

_typedef 
struct vartab {
    char const* name;
    int * var;
} vartab;


vartab varTable[] = {
    { "foo", &foo },
    { "bar", &bar }
};
_

次に、問題の変数名をテーブルで検索し、名前とポインターが指すデータをダンプする小さなルーチンを使用しました。プレーンな整数以外のデータをダンプする必要がある場合は、構造を拡張してprintfスタイルのフォーマッターも保持し、ポインターを_void*_に変更して、そのジャンクをsnprintf()または何かに渡すことができます。データをフォーマットします。

テーブルの作成に役立つマクロを使用することもあります(おそらく変数の宣言も行います)。しかし、正直に言うと、それは本当に理解を複雑にするだけであり(特に、プロジェクトに新しく参加した人にとっては、「WTF?」の瞬間が小さいことが多い)、実際にはそれほど単純化しないと思います。

4
Michael Burr

多くの場合、人々はプログラムを自己内省(または現在の専門用語に「反映」)することを望んでいます。しかし、ほとんどのプログラミング言語は、プログラムのすべての詳細(変数名、関数名、型、式の構造など)を反映する機能をほとんど(Javaなど)提供しないか、または提供しません(C)。

すべての言語でこれを行う方法があります:言語をステップ 、言語からその情報を抽出するように設計されたツールを使用します。これを実行できるツールのクラスは、プログラム変換システムと呼ばれます。

プログラム変換システムを使用して「変数名を取得」して値を出力する方法については、SO回答を参照してください。 変数の変更を自動的に追跡する

3
Ira Baxter

これを試して。

#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable)

コード(void)変数は無効な変換であり、コンマ演算子とマクロ文字列化があります。したがって、最終的な結果はconst char *であり、コンパイラーチェックを含む変数名は実際に存在する変数です。

これで変数の名前が取得され、printf()を使用してその値を出力できます。

2
Timmy_A

実行可能ファイルがデバッグ情報付きでコンパイルされている場合、この情報を取得できる可能性があります。そうでない場合は、おそらく運が悪いでしょう。デバッガを構築しているのですか?どうして? cの既存のデバッガーは非常に成熟しています。ホイールを再発明する代わりに、既存のツールを使用してみませんか?

1
Asaph

あなたのプログラムの中からそれを行う良い方法はありません、私は恐れています(Anacrolixの答えは別として)。あなたの問題に対する正しい解決策はデバッガスクリプトだと思います。ほとんどのデバッガーでは、デバッガーがプログラムの実行を中断するたびに実行するようにフックアップすることもできます(ブレークポイント、^Cなど)、操作するたびにプログラムの状態のスナップショットを取得します。

1
Carl Norum

@ Matt Joinerからの非常に正確な回答にもかかわらず、完全な短いコードを記述して、これがどのように単純かを確認します#defineマクロを使用しています

#include <stdio.h>
#define dump(v)printf("%s",#v);
int main()
    {
    char a;
    dump(a);
    }

出力: a

1
PYK