どこかでこのインタビューの質問に出くわしました、
Cでは、変数が与えられたx
場合、その変数のスペースがスタックまたはヒープに割り当てられているかどうかをどのように確認しますか?
(プログラムでそれを見つけ、シンボルテーブルなどを調べる必要がない方法はありますか?また、スペースがスタックまたはヒープに割り当てられているかどうかを見つけることは、実際的な意味がありますか?)
どこかでこのインタビューの質問に出くわしました、
Cでは、変数が与えられたx
場合、その変数のスペースがスタックまたはヒープに割り当てられているかどうかをどのように確認しますか?
(プログラムでそれを見つけ、シンボルテーブルなどを調べる必要がない方法はありますか?また、スペースがスタックまたはヒープに割り当てられているかどうかを見つけることは、実際的な意味がありますか?)
いいえ、一般的ではありません。
gccを知っています-fsplit-stack
か?
連続スタックを割り当てるか、ブロックがメモリ内のヒープブロックとインターリーブされるスタックを割り当てるかは、実装次第です。ブロックがヒープに割り当てられたのか、スタックが分割されたときにスタックに割り当てられたのかを理解するために頑張ってください。
スタックをヒープよりも大きなアドレスに格納するアーキテクチャで作業している場合は、変数アドレスをスタックの最下位と比較できます。スレッドAPIを使用するpthread
と、この比較は次のようになります。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <inttypes.h>
int is_stack(void *ptr)
{
pthread_t self = pthread_self();
pthread_attr_t attr;
void *stack;
size_t stacksize;
pthread_getattr_np(self, &attr);
pthread_attr_getstack(&attr, &stack, &stacksize);
return ((uintptr_t) ptr >= (uintptr_t) stack
&& (uintptr_t) ptr < (uintptr_t) stack + stacksize);
}
テスト:
int main()
{
int x;
int *p1 = malloc(sizeof(int));
int *p2 = &x;
printf("%d %d\n", is_stack(p1), is_stack(p2));
return 0;
}
...期待どおりに印刷0 1
します。
上記のコードは、他のスレッドのスタックからストレージを検出しません。そのためには、コードで作成されたすべてのスレッドを追跡する必要があります。
これは標準では保証されませんが
ほとんどのプラットフォームでは、スタックは使用可能な最上位アドレスから減少し、ヒープは、アドレスの最上位バイトがプラットフォームで使用可能なメモリスペースの上半分にあり、ギガバイトのメモリを割り当てていない場合、下から増加します。 、それはスタック上にあるのはかなり良い賭けです。
#include <iostream>
#include <stdlib.h>
int main()
{
int x = 0;
int* y = new int;
unsigned int a1 = (int) &x;
unsigned int a2 = (int) y;
std::cout<<std::hex<<a1<<" "<<a2<<std::endl;
}
ffbff474 21600
私がこれを入力しているマシンの出力を提供します。
トリックの質問かもしれません。変数には、自動または静的の保存期間[*]があります。少なくともレジスタに最適化されていない場合、自動は「スタック上」に割り当てられていると言っても過言ではありません。「スタック」が存在することは標準の要件ではありませんが、準拠するC実装は、呼び出しスタックを維持し、自動変数を呼び出しスタックのレベルに関連付ける必要があります。したがって、実際の動作の詳細が何であれ、それを「スタック」と呼ぶことができます。
静的ストレージ期間を持つ変数は、通常、1つ以上のデータセクションに存在します。OSのPOVからは、プログラムが開始する前にヒープからデータセクションが割り当てられる場合がありますが、プログラムのPOVからは、「フリーストア」とは関係ありません。
ソースでの定義を調べることで、変数の保存期間を知ることができます。関数スコープ内にある場合は、マークが付いていない限り自動的に行われstatic
ます。関数スコープにない場合は、マークされているかどうかに関係なく、静的な期間がありますstatic
(static
キーワードはそこで何か違うことを意味するため)。
変数の保存期間をそのアドレスから区別する移植可能な方法はありませんが、特定の実装はそれを行う方法、または推測するために多かれ少なかれ信頼性で使用できるツールを提供する場合があります。
オブジェクトは動的な保存期間(通常、「ヒープに割り当てられた」が意味するもの)を持つこともできますが、そのようなオブジェクトは変数ではないため、存在する場合はそれがトリックになります。
[*]またはC11およびC++11ではスレッドローカル。
解決策はないと思います。コードはスタック(ヒープ)アドレススコープによってvarのアドレスを調整する場合がありますが、正確な方法ではありません。せいぜい、コードは特定のプラットフォームでのみ実行できます。
いいえ、メモリの場所によって、コンパイラが移植可能であるためにisstack()でそれをサポートする必要があるかどうかを判断することはできません。