私は関数ポインタを学んでいます.関数ポインタを使用して関数を指すことができることを理解しています.次に、それらはメモリにとどまると仮定します.それらはスタックまたはヒープに留まりますか?それらのサイズを計算できますか?
9 に答える
コード用のスペースは、コードをビルドするときにリンカーによって静的に割り当てられます。コードがオペレーティングシステムによってロードされる場合、OSローダーはOSからメモリを要求し、コードがOSにロードされます。同様に、その名前が示すように、静的データは、初期スタックと同様に、この時点で割り当てられます(ただし、追加のスレッドが作成されると、さらにスタックが作成される可能性があります)。
関数のサイズの決定に関して、この情報はリンカーに認識されており、ほとんどのツールチェーンでは、リンカーはすべての静的メモリオブジェクト(つまり、実行時にインスタンス化されていないオブジェクト)のサイズと場所を含むマップファイルを作成できます。スタックまたはヒープの時間)。
実行時に関数のサイズを決定する保証された方法はありません(そしてそうする理由はほとんどありません)が、リンカーがソースコード内でメモリ内で順番に隣接する関数を見つけたと仮定すると、次のようになります。関数のサイズの表示:
int first_function()
{
...
}
void second_function( int arg )
{
...
}
int main( void )
{
int first_function_length = (int)second_function - (int)first_function ;
int second_function_length = (int)main - (int)second_function ;
}
ただし、YMMV; これをVC++で試しましたが、「リリース」ビルドでのみ有効な結果が得られました。「デバッグ」ビルドの結果は、実際には意味がありませんでした。この演習は興味を引くためだけのものであり、実用的ではないことをお勧めします。
もちろん、コードのサイズを監視するもう1つの方法は、たとえばデバッガーでコードの逆アセンブルを確認することです。
関数は、テキスト セグメント (「ヒープ」である場合とそうでない場合があります) または使用するアーキテクチャの同等の部分です。サイズに関するコンパイル後のデータはありません。せいぜい、シンボル テーブルからエントリ ポイントを取得できます (利用可能である必要はありません)。そのため、遭遇するほとんどの C 環境で実際にサイズを計算することはできません。
それらは(通常)スタックまたはヒープから分離されています。
それらのサイズを見つける方法はありますが、どれもポータブルに近いものはありません. サイズを知る必要がある、または知りたいと考えている場合は、避けるべきことを行っている可能性が非常に高いです。
簡単にするために、スタックとヒープは読み書き可能なメモリであるのに対し、関数は読み取り専用データであるため、通常はスタックまたはヒープに入りません。
実行時にそのサイズを本当に知る必要がありますか? いいえの場合は、objdump -t -i .text a.out
a.out がバイナリの名前である単純な方法で取得できます。.text
リンカがコードを配置する場所であり、ローダーはこのメモリを読み取り専用 (または単に実行専用) にすることを選択できます。はいの場合、以前の投稿で回答されているように、それを行う方法はありますが、トリッキーで移植性がありません... Clifford は最も簡単な解決策を提供しましたが、リンカがそのような順次的な方法で関数を最終的に配置することはめったにありませんバイナリ。もう 1 つの解決策は、プラグマを使用してリンカー スクリプトでセクションを定義し、関数を含む SIZEOF(...) セクションでリンカーによって埋められるグローバル変数用のストレージを予約することです。これはリンカーに依存しており、すべてのリンカーがこの機能を提供しているわけではありません。
前述のように、関数のサイズはコンパイル時にコンパイラによって生成され、すべてのサイズはリンク時にリンカーに認識されます。どうしても必要な場合は、リンカに開始アドレス、サイズ、そしてもちろん名前を含むマップ ファイルをキックさせることができます。その後、実行時にコードでこれを解析できます。しかし、C の限界を超えずに実行時にそれらを計算するための移植可能で信頼できる方法はないと思います。
Linux カーネルは、これを実行時のプロファイリングに同様に使用します。
Cにはガベージコレクターがありません。何かへのポインタがあるからといって、それがメモリにとどまるわけではありません。
関数は、使用するかどうか、ポインタを保持するかどうかに関係なく、常にメモリ内にあります。
動的に割り当てられたメモリは解放できますが、それへのポインタを保持することとは何の関係もありません。解放したメモリへのポインタを保持するべきではありません。また、ポインタを失う前に解放する必要がありますが、言語は自動的にそれを行いません。
関数のサイズのようなものがある場合、それは STACK FRAME SIZE である必要があります。または、あなたによると、関数のサイズを正確に考えてみてください。静的サイズ、つまり、メモリにロードされたときのすべてのオペコードのサイズを意味しますか?それが意味するものである場合、それを見つけるための言語提供機能が表示されません. hack.たくさんあります.しかし、私はそれを試していません.
#include<stdio.h>
int main(){
void demo();
int demo2();
void (*fun)();
fun = demo;
fun();
printf("\n%lu", sizeof(demo));
printf("\n%lu", sizeof(*fun));
printf("\n%lu", sizeof(fun));
printf("\n%lu", sizeof(demo2));
return 0;
}
void demo(){
printf("tired");
}
int demo2(){
printf("int type funciton\n");
return 1;
}
答えが得られることを願っています。すべての関数はどこかに保存されています
ここでコードの出力