6

Cプログラムで実行時に関数の引数と変数の名前の型を知ることは可能ですか? たとえば、関数がある場合:

int abc(int x, float y , somestruct z ){
    char a;
    int b ;
}

この関数内で、引数変数abc()の名前を知ることができますか?xyzabintfloatsomestructcharint

別の機能がある場合は、次のように言います。

float some_func(specialstruct my_struct, int index){

} 

my_struct引数名は、index型はspecialstruct、であることを知っておく必要がありますint

実行時にこの情報が必要ですか?

ベース ポインターとリターン アドレスにアクセスできます。上記のポインターを使用して必要な情報を取得できますか。

戻りアドレスとdladdr()関数を使用して関数名を抽出できました。

GDBはこれを行うので、この情報を抽出することは可能でしょうか?

4

4 に答える 4

1

他の人が指摘したように、リフレクションは C または C++ 言語に組み込まれていません。ここにはさまざまなアイデアがあります

ただし、リフレクションは、C/C++ でサード パーティのライブラリとデバッグ シンボルを実行可能ファイルまたは外部ファイルに使用することで可能です。

実行可能ファイルはdwarfdump、多かれ少なかれあなたが望んでいることを行います。関数、変数、型などの DWARF 情報の詳細が利用可能です。同様に、libdwarfdump 機能をプロセスで使用して、プロセス自体を検査することもできます。

簡単なマニュアルの例を次に示します。

typedef struct somestruct 
{
   int i;
   int j;
} somestruct ;

int abc(int x, float y , struct somestruct z ){
    char a;
    int b ;
}


int main(int argc, char* argv[])
{

   struct somestruct z;
   abc(1,1.0f,z);
   return 0;
}

および dwarfdump からの部分的な出力

< 1><0x00000055>    DW_TAG_subprogram
                      DW_AT_external              yes(1)
                      DW_AT_name                  "abc"
                      DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                      DW_AT_decl_line             0x00000009
                      DW_AT_prototyped            yes(1)
                      DW_AT_type                  <0x0000004e>
                      DW_AT_low_pc                0x004004ed
                      DW_AT_high_pc               <offset-from-lowpc>18
                      DW_AT_frame_base            len 0x0001: 9c: DW_OP_call_frame_cfa
                      DW_AT_GNU_all_call_sites    yes(1)
                      DW_AT_sibling               <0x000000ad>
< 2><0x00000076>      DW_TAG_formal_parameter
                        DW_AT_name                  "x"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x0000004e>
                        DW_AT_location              len 0x0002: 916c: DW_OP_fbreg -20
< 2><0x00000082>      DW_TAG_formal_parameter
                        DW_AT_name                  "y"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x000000ad>
                        DW_AT_location              len 0x0002: 9168: DW_OP_fbreg -24
< 2><0x0000008e>      DW_TAG_formal_parameter
                        DW_AT_name                  "z"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x0000002d>
                        DW_AT_location              len 0x0002: 9160:        DW_OP_fbreg -32

注意深く調べると、フラグメントが引数 x、y、z を持つ関数 'abc' を定義していることがわかります。

パラメータ x の型は、キー 0x4e を持つ型テーブルへの間接指定です。

出力の別の場所を見ると、タイプ 0x4e の定義を確認できます。タイプ 0x2d は、パラメーター z に結び付けられる somestruct です。

< 1><0x0000002d>    DW_TAG_structure_type
                      DW_AT_name                  "somestruct"
                      DW_AT_byte_size             0x00000008
                      DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                      DW_AT_decl_line             0x00000003
                      DW_AT_sibling               <0x0000004e>

< 1><0x0000004e>    DW_TAG_base_type
                      DW_AT_byte_size             0x00000004
                      DW_AT_encoding              DW_ATE_signed
                      DW_AT_name                  "int"

ptrace、ELF、DWARF、および /proc ファイルシステムの組み合わせにより、gdb はプロセスの静的および動的情報を読み取ることができます。別のプロセスで同様の機能を使用して、リフレクション機能を作成できます。

この戦略の変形を使用して、カスタム デバッガーとメモリ リーク検出器を作成しました。ただし、この戦略がビジネスロジックに使用されているのを見たことがありません。

于 2016-09-15T14:21:51.617 に答える
1

C でこれを行うためのネイティブな方法は実際にはありません。他の言語では、探しているのはリフレクションです。マクロといくつかのトリックでチーズを作ることができますが、基本的な原則として、コンパイル時に変数名と引数を知っている必要があります。

于 2016-09-15T08:35:12.507 に答える
0

共有ライブラリ関数によって提供され、名前からアドレスへの変換、およびその逆の変換を提供する、イントロスペクションの限定された方法がありdlsymますdladdr。ただし、これは C 言語の一部ではなく、OS ダイナミック ローダーによって提供される関数です。ただし、たとえば、見つけたシンボルが変数なのか関数なのかを推論することはできません。

backtraceなどは、関数の呼び出しスタック (呼び出し履歴) を分析できるようにする標準の GNU 拡張機能を構成しています。バイナリにシンボル (関数名) がまだ存在backtrace_symbolsする場合は、それらを取得できます。

__LINE__および定義済みマクロは、現在__FILE__の場所をダンプする方法も提供し、トレース用の非常に便利なマクロの基礎となる場合があります。

それだけです。C はそれ以上のイントロスペクションを提供しません。パラメーターの名前と型はバイナリでなくなり、関数のシグネチャもなくなり、関数の結果の型もなくなりました。

于 2016-09-15T09:15:31.673 に答える