EOF คืออะไรและจะทริกเกอร์ได้อย่างไร [ปิด]


12

นี่คือรหัสที่มา C ของฉัน

เมื่อฉันสร้างมันใน Ubuntu มันเริ่มได้ตัวละคร แต่ฉันไม่รู้ว่าจะจบโปรแกรมอย่างไรเพราะมันไม่จบด้วยการป้อนENTERหรือการคืนรถ

EOF หมายถึงอะไร ฉันจะทริกเกอร์มันได้อย่างไร

แหล่งข้อมูลนี้อยู่ในหนังสือของ Dennis Ritchie ด้วย:

#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เป็นค่าคงที่มาโคร
Edward Torvalds

1
การอ่านที่เกี่ยวข้อง: stackoverflow.com/q/12389518/3701431
Sergiy Kolodyazhnyy

@edwardtorvalds เข้า-1เป็น input ไม่ทำงาน :)
Sergiy Kolodyazhnyy

ฉันคิดว่าหนังสือ Dennis Ritchie เล่มเดียวกันอธิบายเรื่องนี้
andy256

ที่เกี่ยวข้องเพิ่มเติม: unix.stackexchange.com/questions/110240/… (ไม่มีคำตอบที่โพสต์คำถามนี้ถูกต้องทั้งหมด)
fkraiem

คำตอบ:


23

tl; DR

โดยทั่วไปคุณสามารถ "ทริกเกอร์ EOF" ในโปรแกรมที่รันในเทอร์มินัลโดยมีCTRL+ การDกดแป้นพิมพ์หลังจากล้างข้อมูลอินพุตสุดท้าย


EOF หมายถึงอะไร ฉันจะทริกเกอร์มันได้อย่างไร

EOF หมายถึงการสิ้นสุดไฟล์

"การเรียกใช้ EOF" ในกรณีนี้หมายความว่า "ทำให้โปรแกรมทราบว่าจะไม่มีการป้อนข้อมูลเพิ่มเติม"

ในกรณีนี้เนื่องจากgetchar()จะส่งคืนจำนวนลบหากไม่มีการอ่านอักขระการดำเนินการจะถูกยกเลิก

แต่สิ่งนี้ไม่เพียงใช้กับโปรแกรมเฉพาะของคุณเท่านั้น แต่ยังใช้กับเครื่องมือต่างๆ

โดยทั่วไป "ทริกเกอร์ EOF" สามารถทำได้ด้วยการกดแป้นCTRL+ Dหลังจากล้างอินพุตสุดท้าย (เช่นโดยการส่งอินพุตว่าง)

ตัวอย่างเช่นcat:

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

สิ่งที่เกิดขึ้นภายใต้ประทุนเมื่อกดปุ่มCTRL+ Dคืออินพุตที่ป้อนตั้งแต่ฟลัชอินพุตสุดท้ายถูกฟลัช เมื่อเกิดเหตุการณ์นี้จะเป็นอินพุทที่ว่างเปล่าread()syscall เรียกโปรแกรมผลตอบแทน STDIN 0, getchar()ส่งกลับจำนวนลบ ( -1ในห้องสมุด GNU C) และนี่คือในทางกลับตีความว่าเป็น EOF 1


1 - /programming//a/1516177/4316166


2
การรวบรวมทำงานได้เนื่องจากการคั่นด้วยเครื่องหมายจุลภาคไม่ถูกผูกไว้โดยอยู่ในบรรทัดเดียวกัน อื่น ๆ กว่าที่คำอธิบายที่ดีใน EOF :)
Paulius Šukys

@ PauliusŠukys Huh คุณพูดถูก My C เป็นสนิมเล็กน้อย :)
คอส

1
iirc EOF ไม่ได้กำหนดไว้ที่ -1 ต่อมาตรฐาน มันเป็นเพียงสิ่งที่มันเกิดขึ้นใน glibc เช่น
larkey

1
@larkey นั่นเป็นที่ถูกต้อง: gnu.org/software/libc/manual/html_node/EOF-and-Errors.html
คอส

1
EOF ไม่ได้ 'รวมในการส่ง "อินพุตว่าง" และคำตอบ SO ที่คุณอ้างไม่ได้พูดเป็นอย่างอื่น มันเป็นสัญญาณออกจากวง ในกรณีของเทอร์มินัลจะถูกส่งโดยพิมพ์ Ctrl / d
user207421

4

TL; DR : EOF ไม่ใช่ตัวอักษร แต่เป็นมาโครที่ใช้สำหรับประเมินผลตอบแทนเชิงลบของฟังก์ชั่นอ่านอินพุต หนึ่งสามารถใช้Ctrl+ Dเพื่อส่งEOTตัวละครซึ่งจะบังคับให้กลับมาทำงาน-1

โปรแกรมเมอร์ทุกคนต้อง RTFM

ให้เราอ้างอิงถึง "คู่มืออ้างอิง CA" โดย Harbison และ Steele, 4th ed จาก 1995 หน้า 317:

จำนวนเต็มลบ EOF คือค่าที่ไม่ใช่การเข้ารหัสของ "อักขระจริง" . . ตัวอย่างเช่น fget (ส่วนที่ 15.6) จะส่งคืน EOFเมื่อสิ้นสุดไฟล์เนื่องจากไม่มี "อักขระตัวจริง" ที่ต้องอ่าน

เป็นหลักEOFไม่ได้เป็นตัวอักษร แต่ค่อนข้างค่าจำนวนเต็มดำเนินการในการเป็นตัวแทนของstdio.h -1ดังนั้นคำตอบของ kos นั้นถูกต้องที่สุดเท่าที่จะทำได้ แต่ไม่เกี่ยวกับการรับอินพุต "ว่าง" หมายเหตุสำคัญคือที่นี่ EOF ทำหน้าที่เป็นการเปรียบเทียบค่าส่งคืน (จากgetchar()) ไม่ใช่เพื่อแสดงถึงอักขระจริง man getcharสนับสนุนว่า

คืนค่า

fgetc (), getc () และ getchar () ส่งคืนอักขระที่อ่านเป็นอักขระแคสต์ที่ไม่ได้ลงชื่อไปยัง int หรือ EOF เมื่อสิ้นสุดไฟล์หรือข้อผิดพลาด

ได้รับ () และ fgets () กลับ s เมื่อประสบความสำเร็จและ NULL จากข้อผิดพลาดหรือเมื่อสิ้นสุดไฟล์เกิดขึ้นในขณะที่ไม่มีการอ่านตัวอักษร

ungetc () ส่งคืน c เมื่อสำเร็จหรือ EOF เนื่องจากข้อผิดพลาด

พิจารณาwhileห่วง - จุดประสงค์หลักของมันคือการทำซ้ำการกระทำถ้าเงื่อนไขในวงเล็บเป็นจริง ดูอีกครั้ง:

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

โดยทั่วไปแล้วจะบอกว่าทำสิ่งต่าง ๆ ถ้า c = getchar()ส่งคืนรหัสที่ประสบความสำเร็จ ( 0หรือเหนือกว่านั้นมันเป็นเรื่องปกติโดยวิธีลองใช้คำสั่งที่ประสบความสำเร็จจากecho $?นั้นก็ล้มเหลวecho $?และดูตัวเลขที่พวกเขากลับมา) ดังนั้นหากเราได้รับตัวอักษรและ assing ไปที่ 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 ไม่ใช่อักขระจริงอย่างไรก็ตามมีอักขระEOT(สิ้นสุดการส่ง) ซึ่งมีค่าทศนิยม ASCII เป็น 04; มันถูกลิงค์ไปยังCtrl+ Dทางลัด (แสดงด้วยเช่นกันว่าเป็นอักขระเมตา^D) จุดจบของตัวส่งกำลังใช้เพื่อแสดงถึงการปิดกระแสข้อมูลย้อนกลับเมื่อคอมพิวเตอร์ถูกใช้เพื่อควบคุมการเชื่อมต่อโทรศัพท์ดังนั้นการตั้งชื่อ "สิ้นสุดการส่งสัญญาณ"

ดังนั้นจึงเป็นไปได้ที่จะส่งค่า ascii ไปยังโปรแกรมเช่นนั้นโปรดสังเกต$'\04'ว่า EOT คืออะไร:

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

ดังนั้นเราสามารถพูดได้ว่ามันมีอยู่ แต่ไม่สามารถพิมพ์ได้

หมายเหตุด้านข้าง

เรามักจะลืมว่าในคอมพิวเตอร์ที่ผ่านมาไม่ได้เป็นอเนกประสงค์ - นักออกแบบจะต้องใช้ประโยชน์จากแป้นพิมพ์ทุกปุ่มใช้ได้ ดังนั้นการส่งEOTอักขระด้วย CtrlD ยังคงเป็น "การส่งอักขระ" ซึ่งไม่เหมือนกับการพิมพ์ตัวใหญ่ A, ShiftA คุณยังคงให้อินพุตกับคีย์ที่มีอยู่ในคอมพิวเตอร์ ดังนั้น EOT จึงเป็นตัวละครที่แท้จริงในแง่ที่ว่ามันมาจากผู้ใช้มันสามารถอ่านได้โดยคอมพิวเตอร์ (แม้ว่าจะไม่สามารถพิมพ์ได้หรือไม่สามารถมองเห็นได้โดยมนุษย์) มันมีอยู่ในหน่วยความจำคอมพิวเตอร์

ความคิดเห็นของผู้บัญชาการไบต์

หากคุณพยายามอ่านจาก / dev / null นั่นควรจะส่งคืน EOF ด้วยใช่ไหม หรือฉันจะไปที่นั่นอะไร

ใช่ถูกต้องเพราะ/dev/nullไม่มีตัวอักษรจริงที่จะอ่านดังนั้นมันc = getchar()จะส่งคืน-1รหัสและโปรแกรมจะออกทันที คำสั่งอีกครั้งจะไม่ส่งคืน EOF EOF เป็นเพียงตัวแปรคงที่เท่ากับ -1 ซึ่งเราใช้ในการเปรียบเทียบรหัสการกลับมาของฟังก์ชั่น ไม่ได้อยู่ในฐานะตัวละครมันเป็นเพียงแค่ภายในค่าคงที่EOFstdio.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

เล็บอีกอันในโลงศพ

บางครั้งมีการพยายามพิสูจน์ว่า EOF เป็นอักขระที่มีรหัสดังนี้:

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

ปัญหาที่เป็นที่ประเภทข้อมูลถ่านสามารถเป็นค่าที่ลงนามหรือไม่ได้ลงนาม นอกจากนี้ยังเป็นประเภทข้อมูลที่เล็กที่สุดซึ่งทำให้เป็นประโยชน์อย่างมากในไมโครคอนโทรลเลอร์ที่หน่วยความจำมี จำกัด ดังนั้นแทนที่จะประกาศ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 เป็นสตริง

#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);

ค่าเลขฐานสิบหก

พิมพ์ EOF เป็นค่าฐานสิบหกให้FFFFFFFFเป็น 16 บิต (8 ไบต์) -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เราจะได้ค่าฐานสิบ 41 อย่างเห็นได้ชัดเหมือนกับในตาราง ASCII แต่สำหรับ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  }

หลามเกี่ยวกับอะไร

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

จุดที่ดีแน่นอนตัวละครจะถูกส่งอย่างใดในบางจุด
kos

ฉันคิดว่าตัวละคร EOF เป็นสิ่งที่ขาดหายไปในการแปลเพราะมันไม่ใช่ตัวละครที่แท้จริง แต่ EOT เป็นตัวละคร ASCII ที่แท้จริง ไปคิด!
Sergiy Kolodyazhnyy

1
หากคุณพยายามอ่านจาก/dev/nullนั้นควรส่งคืน EOF ด้วยใช่ไหม หรือฉันจะไปที่นั่นอะไร
ผู้บัญชาการ Byte

@ ByteCommander ให้หา ทำ cat / dev / null | แมว -
Sergiy Kolodyazhnyy

@ByteCommander เพิ่มส่วนที่อยู่ความคิดเห็นของคุณ
Sergiy Kolodyazhnyy

2

EOFย่อมาจากจุดสิ้นสุดของแฟ้ม ในขณะที่ฉันไม่ทราบวิธีการทริกเกอร์สัญลักษณ์ต่อไปนี้คุณสามารถเรียกใช้โปรแกรมต่อไปนี้ผ่านการไพพ์ไฟล์ซึ่งส่งสัญญาณEOFที่ส่วนท้าย:

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

a.outแหล่งรวบรวมของคุณอยู่ที่ไหน


1
โหวตขึ้นแล้ว แต่ในบันทึกด้าน EOF ไม่ใช่ตัวละครฉันคิดว่าความเข้าใจผิดเกิดขึ้นจากความจริงที่ส่งสัญญาณผ่านการกดแป้น CTRL ซึ่งมักจะเป็นวิธีป้อนอักขระที่ไม่สามารถพิมพ์ได้ ตามที่ฉันเข้าใจทุกสิ่งที่เกิดขึ้นจริงคืออินพุตทั้งหมดถูกฟลัชและการป้อนข้อมูลให้ล้างข้อมูลว่างเปล่าread()(syscall) จะกลับมา0ซึ่งจะถูกตีความเป็น EOF: stackoverflow.com/a/1516177/4316166
kos

@ kos คุณพูดถูกมันเป็นสัญญาณหลังจากนั้น
Paulius Šukys
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.