10

関数ポインタ(関数のマシンコードが格納されているアドレスを指すポインタ)について学びました。これにより、マシンコードとそれがメモリにどのように格納されるかについて考えさせられました。

マシンコードはメモリに連続して保存されているので、次/前の関数を指すまでポインタを「手動で」増やすことができますか?

これは、デバッガーが行うことですか?彼は私にプログラムカウンターがマシンコードのどこを指しているのかを「見る」ようにさせてくれますか?

結論:関数ポインターを使用してプリミティブデバッガーをプログラムできますか?

私はこの権利を理解しましたか、それとも私は道を外れていますか?

4

5 に答える 5

8

私が追跡したドラフトC標準(N1124)を使用すると、同様のルールがあります。加算式に関するセクション(§6.5.6/ 2)は次のように述べています

さらに、両方のオペランドが算術型であるか、一方のオペランドがオブジェクト型へのポインタである必要があります。

そして、オブジェクトタイプは§6.2.5/1で次のように定義されています。

オブジェクトに格納されている値または関数によって返される値の意味は、オブジェクトへのアクセスに使用される式のタイプによって決まります。(オブジェクトとして宣言された識別子は、そのような式の中で最も単純です。型は識別子の宣言で指定されます。)型は、オブジェクト型(オブジェクトを完全に記述する型)、関数型(関数を記述する型)、およびに分割されます。不完全な型(オブジェクトを説明するが、そのサイズを決定するために必要な情報が不足している型)。

関数型はオブジェクト型とは異なるため、これは関数ポインタでのポインタ演算が禁止されていることを示しています。

C ++では、この操作は不正です。§5.7/1で与えられているポインタ加算の定義は次のように述べています。

さらに、両方のオペランドが算術型または列挙型であるか、一方のオペランドが完全に定義されたオブジェクト型へのポインタであり、もう一方が整数型または列挙型である必要があります。

ただし、§3.9/9は次のように述べています

オブジェクト型は、関数型でも、参照型でも、void型でもない(おそらくcv修飾された)型です。

まとめると、これは、C++では関数ポインターをインクリメントできないことを意味します。

お役に立てれば!

于 2011-02-23T00:02:18.110 に答える
5

あなたはこのようなことをすることができます(または少なくともできます)が、それは明らかに自明ではありません。まず第一に、関数ポインタを実際にインクリメントまたはデクリメントすることはできません-それはアドレスを指しますが、ポインタの計算は通常の増分で行われますsizeof(pointed to type)-しかし、関数では意味がないので、できませんその上で数学を行います。

ほとんどのデバッガーは、アドレスを行番号、関数名、変数名などに関連付けるデバッグ情報を使用して(主に)動作します。

于 2011-02-22T23:45:08.817 に答える
4

すこし。関数は、ソースコードと同じようにメモリに配置されると想定しています。ほとんどの場合、それらはそうではありません-コンパイラは通常、それらをすべての意地悪なものに移動します。

ただし、実行できることは、現在の命令へのポインターを使用してコードをステップ実行し、そのカウンターを特定の量だけインクリメントして次の命令に到達することです。ただし、その場合は、関数の先頭を指しているだけではないため、関数ポインターとは呼ばなくなります。代わりに、これを命令ポインタと呼びます。

実際、これはまさにコンピューターの動作です。プログラムカウンターと呼ばれる特殊レジスターがあり、常に現在の命令を指し、命令ごとに一定量ずつインクリメントしますコマンドはプログラムに値を書き込むのと同じです)。カウンター)GOTO

ただし、現実の世界では、これはデバッガーの動作方法ではありません。実際、関数ポインター以外に、Cのメモリ内のコードセグメントへのポインターポイントを設定できるかどうかさえわかりません。多くの場合、この手法を使用する必要があるのは、別のプロセッサタイプのエミュレータを作成するなど、プログラムカウンタをシミュレートする必要がある場合のみです。

于 2011-02-22T23:48:54.560 に答える
2
  1. マシンコードは連続して保存することはできません。コンパイラーは、(最適化で)いくつかの関数を自由に分割またはマージできます
  2. 関数へのポインタを手動で増やすと、おそらく関数の途中に入るでしょうが、これは間違っています。
  3. デバッグルーチンはすでに利用可能です。現在の実行ポイントのスタックトレースを取得し、スタック内の実行ポインタが属する関数名を解決できます(man backtraceman backtrace_symbols)。を使用addr2lineすると、それらを行番号に変換できます。
于 2011-02-22T23:44:46.413 に答える
1

個々の関数がメモリ内のどこにあるかについての保証はありません。

関数自体は(CPUが命令を順番に実行するため)メモリの連続ブロックになりますが、コードの最適化を有効にすると、関数自体とは似ていない場合があります(命令が大幅に並べ替えられる場合があります)。別の関数からクリーンアップコードを借用することもできます。

プリミティブデバッガーを作成することもできますが、関数がどこで終了するかを見つけるのは簡単ではありません。

于 2011-02-22T23:44:48.973 に答える