6

http://www-ee.eng.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html このページには、渡されたローカル変数とパラメーターがスタックに割り当てられていると書かれているので、試してみました:

#include <stdio.h>
#include <stdlib.h>
#define A 2000000
#define B 2

typedef struct {
    int a[A][A];
} st;

void fun(st s){}

void main()
{
    st s;
    //fun(s);
}

コンパイルして実行した後、エラーは報告されません。しかし、私がアノテーションを解除する//fun(s)と、SIGSEGVがキャッチされます。誰でも理由がわかりますか?

4

2 に答える 2

12

ローカル変数はどこに割り当てられますか? ヒープかスタックか?

このページには、渡されたローカル変数とパラメーターがスタックに割り当てられていると書かれています

丁度。

しかし、 //fun(s) のアノテーションを解除すると、SIGSEGV がキャッチされます。誰でも理由がわかりますか?

スタック上のメモリは、ヒープ¹ よりもはるかに制限されています。スタックに 2000000x2000000 配列を割り当ててから、それを関数に渡します。これは、使用可能なスタック スペースを超える可能性が非常に高く、セグメンテーション フォールトを引き起こします。

関数呼び出しがコメントアウトされているときにセグメンテーション違反が発生しない理由について。まず第一に、Jonathan Leffer が指摘したように、コンパイラはs使用されていないため、おそらく完全に最適化されます。しかし、そうでなかったとしても、スタックにメモリを割り当てることは単にスタック ポインターをインクリメントすることを意味するため、segfault は発生しない可能性があります。また、ほとんどの実装では、それ自体がセグメンテーション違反を引き起こすことはありません。セグメンテーション違反は、割り当てられたメモリにアクセスしようとしたときにのみ発生し、システムはスタック (この場合はメモリ全体) の境界を超えていることを認識します。

¹ この場合、slugonamission が指摘したように、配列は 16TB を占有するため、ヒープで使用可能なメモリも超えるため、違いはありません。

于 2013-01-26T02:18:19.297 に答える
3

さらに、これは、関数の引数を値で渡すだけで、通常は引数を参照で渡す良い例です。

#include <stdio.h>
#include <stdlib.h>
#define A 2000000
#define B 2

typedef struct {
    int a[A][A];
} st;

void fun(st *s){}

void main()
{
    st s;
    fun(&s);
}

スタック上に4TBのメモリが必要なため、まったく実行されないと思います。また、未使用の変数がコンパイラーによってダンプされ、実行時にまったく宣言されなかった//fun(s)ため、コード内でスムーズにコンパイルおよび実行されました。s

于 2013-01-26T02:29:29.820 に答える