2

テキストファイルを行ごとに読み取り、その内容をコンソールに出力することを示す単純な C ファイル I/O プログラムがあります。

/**
* simple C program demonstrating how
* to read an entire text file
*/

#include <stdio.h>
#include <stdlib.h>

#define FILENAME "ohai.txt"

int main(void)
{
    // open a file for reading
    FILE* fp = fopen(FILENAME, "r");

    // check for successful open
    if(fp == NULL)
    {
        printf("couldn't open %s\n", FILENAME);
        return 1;
    }

    // size of each line
    char output[256];

    // read from the file
    while(fgets(output, sizeof(output), fp) != NULL)
        printf("%s", output);

    // report the error if we didn't reach the end of file
    if(!feof(fp))
    {
        printf("Couldn't read entire file\n");
        fclose(fp);
        return 1;
    }

    // close the file
    fclose(fp);
    return 0;
   }

1 行あたり 256 文字 ( 32 ビット マシンでは1024バイトビット) のスペースを持つ配列を割り当てたようです。最初の行にohai.txt1000 文字を超えるテキストを入力しても、output[]配列によって指定された割り当てられた使用可能なスペースをオーバーフローしたため、プログラムはセグメンテーション違反を起こしませんでした。

私の仮説は、オペレーティング システムが追加のメモリをプログラムに提供する一方で、追加のメモリをプログラムに提供するというものです。これは、テキスト行によって消費されたメモリohai.txtがスタックオーバーフローになった場合にのみ、プログラムがクラッシュすることを意味します。

テキスト ファイルの 1 行の文字数が 256 よりもはるかに多い場合でも、このプログラムがクラッシュしない理由について、C とメモリ管理の経験が豊富な人がサポートしてくれるか、私の仮説に反論してくれませんか?

4

4 に答える 4

0

スタックの説明と、実際にオーバーフローした場合でもこれが segfault にならない理由 (他の人が指摘しているように、書かれたコードはそうではない)

スタック ポインターは 0x8000000 などのアドレスから始まり、ランタイムが main を呼び出すと、少し下に移動します (そこには他のものがある可能性があるため、main の開始時にスタックにどれだけのものがあるかわかりません)。 main は、すべてのローカル変数に対してスタック ポインターをさらに移動します。したがって、この時点で、配列には 0x8000000 より 256 バイト以上下のアドレスがあり、メインのスタック フレーム全体とメインと呼ばれる他の C ランタイムのスタック フレーム全体を完全に実行しない限り、セグメンテーション違反は発生しません。 .

したがって、簡単にするために、配列が 0x8000000 から 768 バイト下の 0x7fffd00 にあるベース アドレスで終わると仮定します。 main が返されるか、feof を呼び出すと、スタック フレームがランダムな文字でいっぱいになったため、fgets()) 内のセグメンテーション違反について話していますが、書き込み可能な何かがスタックの上のページにマップされている場合でも、それは保証されません (ほとんどの OS とは異なります)。十分にオーバーフローするとセグメンテーション違反が発生するため、これを避けることをお勧めします)

スタックが逆に実行される場合 (つまり、上向きに成長する場合)、最大サイズのスタック全体を実行する必要があります。これは、ユーザー空間では通常非常に大きくなります (32 ビット x86 の Linux のデフォルトは 2MB です)。確かにx86スタックは下向きに成長するので、あなたのケースではそうではありません.

于 2013-08-27T17:36:19.097 に答える