EOFとは何ですか?[閉まっている]


12

これが私のCソースコードです。

Ubuntuでビルドすると、文字を取得し始めますが、入力ENTERやキャリッジリターンで終了しないため、プログラムを終了する方法がわかりません。

EOFの意味?どうすればトリガーできますか?

このソースは、デニスリッチーの本にも掲載されています。

#include <stdio.h>
    /* count digits, white space, others */
main ()
{
  int c, i, nwhite, nother;
  int ndigit[10];
  nwhite = nother = 0;
  for (i = 0; i < 10; ++i)
    ndigit[i] = 0;
  while ((c = getchar ()) != EOF)
    if (c >= '0' && c <= '9')
      ++ndigit[c - '0'];
    else if (c == ' ' || c == '\n' || c == '\t')
      ++nwhite;
    else
      ++nother;
  printf ("digits =");
  for (i = 0; i < 10; ++i)
    printf (" %d", ndigit[i]);
  printf (", white space = %d, other = %d\n", nwhite, nother);
}

4
C言語で-1は、EOFと同等です。/usr/include/stdio.hマクロ定数として定義されています
エドワードトーバルズ

1
関連
資料

入力-1として入力した@edwardtorvaldsが機能しません:)
Sergiy Kolodyazhnyy

同じデニス・リッチーの本がこれを説明していると思います。
andy256

関連:unix.stackexchange.com/questions/110240/…(この質問に投稿された回答のどれも完全に正しいものではありません。)
fkraiem

回答:


22

Tl; dr

通常、最後の入力フラッシュの直後にCTRL+ Dキーストロークで端末で実行されているプログラムで「EOFをトリガー」できます。


EOFの意味?どうすればトリガーできますか?

EOFはファイルの終わりを意味します。

この場合の「EOFのトリガー」とは、おおよそ「入力が送信されないことをプログラムに認識させる」ことを意味します。

この場合、getchar()文字が読み取られない場合は負の数が返されるため、実行は終了します。

ただし、これは特定のプログラムだけでなく、さまざまなツールにも適用されます。

一般に、「EOFのトリガー」は、最後の入力フラッシュの直後に(つまり、空の入力を送信することにより)CTRL+ Dキーストロークで実行できます。

例えばcat

% cat >file # Hit ENTER
foo # Hit ENTER and CTRL+D
% 

CTRL+を押したときにボンネットの下で起こっているのDは、最後の入力フラッシュがフラッシュされてから入力された入力です。これは空の入力であることを起こる場合read()、プログラムのSTDINリターンで呼び出さシステムコール0getchar()(負の数を返し-1GNU Cライブラリ内の)、これは今度はEOFとして解釈される1


1- /programming//a/1516177/4316166


2
コンマ区切りは同じ行にあることに拘束されないため、コンパイルは機能します。それ以外に、EOFの素晴らしい説明:)
パウリウスシュキース

@PauliusŠukysええ、そうです。私のCは少し錆びています。:)
コス

1
iirc EOFは、規格ごとに-1と定義されていません。たとえば、glibcにあるのです。
-larkey


1
EOFは「空の入力」の送信に一貫していないため、引用したSOの回答はそうではありません。これは帯域外信号です。端末の場合、Ctrl / dを入力して送信されます。
user207421

4

TL; DR:EOFは文字ではなく、入力読み取り関数の負の戻り値を評価するために使用されるマクロです。Ctrl+ Dを使用して、EOT関数を強制的に返す文字を送信できます-1

すべてのプログラマーはRTFMをしなければなりません

Harbison and Steele、第4版の「CA Reference Manual」を参照してください。1995年、317ページから:

負の整数EOFは、「実際の文字」のエンコードではない値です。。。たとえば、fget(セクション15.6)、ファイルの終わりでEOFを返します。これは、読み取る「実際の文字」がないためです。

本質的にEOFは文字ではなく、を表すために実装された整数値です。したがって、kosの答えはそれに関する限り正しいですが、「空の」入力を受け取ることについてではありません。重要な注意事項は、ここでは、EOFとしての役割を果たすことである戻り値(の実際の文字を意味するのではなく、比較)。以下をサポートします:stdio.h-1getchar()man getchar

戻り値

fgetc()、getc()、およびgetchar()は、ファイルまたはエラーの終了時にintまたはEOFにキャストされる符号なし文字として読み取られた文字を返します。

gets()およびfgets()は成功するとsを返し、エラーまたは文字が読み取られていないときにファイルの終わりが発生するとNULLを返します。

ungetc()は、成功するとcを返し、エラーの場合はEOFを返します。

whileループを考慮してください。その主な目的は、括弧内の条件がtrueの場合にアクションを繰り返すことです。もう一度見てください:

while ((c = getchar ()) != EOF)

基本的には、c = getchar()成功したコードを返す場合 (0または上記;それは一般的なことです、成功したコマンドを実行してecho $?から失敗しecho $?、返される数字を見る)したがって、文字を取得してCにアッシングすることに成功した場合、返されるステータスコードは0、失敗は-1です。EOFとして定義され-1ます。したがって、条件-1 == -1が発生すると、ループが停止します。そして、いつそれが起こりますか?取得するキャラクターがなくなったとき、c = getchar()失敗したとき。あなたが書くことができwhile ((c = getchar ()) != -1)、それでも動作します

また、実際のコードに戻りましょう、ここからの抜粋です stdio.h

/* End of file character.
   Some things throughout the library rely on this being -1.  */
#ifndef EOF
# define EOF (-1)
#endif

ASCIIコードとEOT

EOF文字は実際の文字ではありませんが、EOTASCII 10進値が04の(伝送終了)文字が存在します。Ctrl+ Dショートカットにリンクされています(メタ文字としても表されます^D)。コンピュータが電話接続を制御するために使用されたときにデータのストリームが閉じられたことを示すために使用される伝送終了特性は、「伝送終了」という命名です。

そのため、そのascii値をそのようにプログラムに送信することが可能です。EOTであることに注意し$'\04'てください。

skolodya@ubuntu:$ ./a.out  <<< "a,b,c $'\04'"                                  
digits = 1 0 0 0 1 0 0 0 0 0, white space = 2, other = 9

したがって、それは存在すると言うことができますが、印刷できません

サイドノート

過去のコンピューターは汎用性が高くなかったことをよく忘れます。デザイナーは利用可能なすべてのキーボードキーを使用する必要があります。したがって、EOTCtrlD を使用して文字を送信することは、大文字のA、ShiftAを入力するのとは異なり、依然として「文字を送信する」ことになります。したがって、EOTはユーザーから来たという意味で実際のキャラクターであり、コンピューターで読み取り可能です(印刷可能ではなく、人間には見えません)が、コンピューターのメモリに存在します

バイトコマンダーのコメント

/ dev / nullから読み取ろうとすると、EOFも返されるはずですよね?それとも私はそこに何を得るのですか?

はい、正確に正しいです。なぜなら、/dev/null読み取るべき実際の文字がないため、コードc = getchar()を返し-1、プログラムはすぐに終了するからです。繰り返しますが、コマンドはEOFを返しません。EOFは、-1に等しい定数変数であり、getchar関数の戻りコードを比較するために使用しますEOF文字としては存在せず、内部の静的な値にすぎませんstdio.h

デモ:

# cat /dev/null shows there's no readable chars
DIR:/xieerqi
skolodya@ubuntu:$ cat /dev/null | cat -A        

# Bellow is simple program that will open /dev/null for reading. Note the use of literal -1                                   
   DIR:/xieerqi
skolodya@ubuntu:$ cat readNull.c                                               
#include<stdio.h>

void main()
{
   char c;
    FILE *file;
    file = fopen("/dev/null", "r");

    if (file) 
    {
    printf ("Before while loop\n");
        while ((c = getc(file)) != -1)
            putchar(c);
    printf("After while loop\n"); 
    fclose(file);
    }
}

DIR:/xieerqi
skolodya@ubuntu:$ gcc readNull.c -o readNull                                   

DIR:/xieerqi
skolodya@ubuntu:$ ./readNull
Before while loop
After while loop

coの中の別の釘

EOFが次のようなコードを持つ文字であることを証明しようとする場合があります。

#include <stdio.h>
int main(void)
{
    printf("%c", EOF);
    return 0;
}

それに関する問題は、charデータ型が符号付きまたは符号なしの値になる可能性があることです。さらに、これらはアドレス可能な最小のデータ型であるため、メモリが限られているマイクロコントローラーで非常に役立ちます。そのため、宣言する代わりにint foo = 25;、小さなメモリchar foo = 25;または同様のものを備えたマイクロコントローラで見ることが一般的です。さらに、文字は署名されている場合と署名されていない場合があります

次のようなプログラムを使用して、バイト単位のサイズを確認できます。

#include <stdio.h>
int main(void)
{
    printf("Size of int: %lu\n",sizeof(int));
    printf("Sieze of char: %lu\n",sizeof(char));
    //printf("%s", EOF);
    return 0;
}

skolodya@ubuntu:$ ./EOF                                                        
Size of int: 4
Sieze of char: 1

ポイントは何ですか?ポイントは、EOFが-1として定義されていることですが、charデータ型は整数値を出力できます

OK 。。.so charを文字列として出力しようとするとどうなりますか?

#include <stdio.h>
int main(void)
{
    printf("%s", EOF);
    return 0;
}

明らかにエラーですが、それでもなお、エラーは興味深いことを教えてくれます。

skolodya @ ubuntu:$ gcc EOF.c -o EOF
EOF.c:関数 'main':EOF.c:4:5:警告:形式 '%s'は型 'char *'の引数を期待しますが、引数2はタイプ 'int' [-Wformat =] printf( "%s"、EOF);

16進値

EOFを16進値として出力するFFFFFFFFと、16ビット(8バイト)の値、aの2の補数が得られます-1

#include <stdio.h>
int main(void)
{
    printf("This is EOF: %X\n", EOF);
    printf("This is Z: %X\n",'Z');
    return 0;
}

出力:

DIR:/xieerqi
skolodya@ubuntu:$ ./EOF                                                        
This is EOF: FFFFFFFF
This is Z: 5A

次のコードでは、別の奇妙なことが起こります。

#include <stdio.h>
int main(void)
{
   char c;
   if (c = getchar())
    printf ("%x",c);
    return 0;
}

Shift+ Aを押すと、明らかなASCIIテーブルと同じ16進値41が得られます。ただし、Ctrl+ Dについてはffffffff、再び-にgetchar()格納されたの戻り値がありcます。

DIR:/xieerqi
skolodya@ubuntu:$ gcc  EOF.c -o ASDF.asdf                                      

DIR:/xieerqi
skolodya@ubuntu:$ ./ASDF.asdf                                                  
A
41
DIR:/xieerqi
skolodya@ubuntu:$ ./ASDF.asdf                                                  
ffffffff

他の言語を参照してください

他の言語は、マクロと比較するのではなく、関数の終了ステータスを評価するために動作するため、この混乱を避けていることに注意してください。Javaでファイルを読み取る方法

    File inputFile  = new File (filename);
    Scanner readFile = new Scanner(inputFile);
    while (readFile.hasNext())
        { //more code bellow  }

pythonはどうですか?

with open("/etc/passwd") as file:
     for line in file:
          print line

素晴らしい点は、確かにある時点でキャラクターが何らかの形で送られることです。
コス

EOF文字は実際の文字ではないため、翻訳で失われたものだと思いますが、EOTは実際のアスキー文字です。フィギュアに行く!
セルギーKolodyazhnyy 16年

1
から読み込もうとすると/dev/null、EOFも返されるはずですよね?それとも私はそこに着くのですか?
バイトコマンダー

@ByteCommanderで調べることができます。cat / dev / null | 猫-A。
セルギーKolodyazhnyy 16年

@ByteCommanderはコメントに対応するセクションを追加しました
Sergiy Kolodyazhnyy

2

EOFファイルの終わりを表します。次のシンボルをトリガーする方法はわかりませんが、ファイルをパイピングして次のプログラムを実行し、最後にEOFシグナルを送信できます。

echo "Some sample text" | ./a.out

a.outコンパイルされたソースはどこですか


1
すでにこれを支持しましたが、サイドノートでEOFは文字ではありませんが、誤解はCTRLキーストロークを介して通知されるという事実から生じると思います。これは通常印刷不可能な文字を入力する方法です。私は理解するように、実際に起こることすべては、すべての入力がフラッシュとフラッシュ空に入力されていることであるread()(システムコール)返され0EOFとして解釈され、:stackoverflow.com/a/1516177/4316166
コス

@kos、あなたは正しい、それは結局シグナルです。
パウリウスシュキース
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.