Menyimpan karakter EOF (End of File) dalam tipe char

11

Saya membaca di buku Bahasa Pemrograman C karya Dennis Ritchie yang intharus digunakan untuk variabel untuk menahan EOF - untuk membuatnya cukup besar sehingga dapat menyimpan nilai EOF - tidak char. Tetapi kode berikut berfungsi dengan baik:

#include<stdio.h> 

main()  { 
  char c; 
  c=getchar(); 
  while(c!=EOF)  { 
    putchar(c); 
    c=getchar(); 
  } 
} 

Ketika tidak ada lagi input, getcharkembalikan EOF. Dan dalam program di atas, variabel c, dengan tipe char, dapat menahannya dengan sukses.

Mengapa ini bekerja? Sesuai penjelasan dalam buku yang disebutkan di atas, kode tidak boleh bekerja.

pengguna1369975
sumber
5
Kode ini cenderung gagal jika Anda membaca karakter dengan nilai 0xff. Menyimpan hasil getchar()dalam intmemecahkan masalah itu. Pertanyaan Anda pada dasarnya sama dengan pertanyaan 12.1 di FAQ comp.lang.c , yang merupakan sumber yang bagus. (Juga, main()seharusnya begitu int main(void), dan tidak ada ruginya menambahkan return 0;sebelum penutupan }.)
Keith Thompson
1
@delnan: Artikel yang ditautkan tidak benar tentang bagaimana Unix memperlakukan kontrol-D. Itu tidak menutup aliran input; itu hanya menyebabkan ketakutan () yang menghalangi konsol untuk segera kembali dengan data apa pun yang belum dibaca. Banyak program mengartikan pengembalian nol-byte dari fread () sebagai indikasi EOF, tetapi file tersebut sebenarnya akan tetap terbuka dan dapat memasok lebih banyak input.
supercat

Jawaban:

11

Kode Anda tampaknya berfungsi, karena konversi tipe implisit terjadi secara tidak sengaja untuk melakukan hal yang benar.

getchar()mengembalikan nilai intdengan nilai yang cocok dengan rentang unsigned charatau adalah EOF(yang harus negatif, biasanya -1). Perhatikan bahwa EOFitu sendiri bukan karakter, tetapi sinyal bahwa tidak ada lagi karakter yang tersedia.

Saat menyimpan hasil dari getchar()dalam c, ada dua kemungkinan. Baik tipe chardapat mewakili nilai, dalam hal ini adalah nilai c. Atau tipe char tidak dapat mewakili nilai. Dalam hal ini, tidak ditentukan apa yang akan terjadi. Prosesor Intel hanya memotong bit-bit tinggi yang tidak cocok dengan tipe baru (secara efektif mengurangi nilai modulo 256 untuk char), tetapi Anda tidak boleh bergantung pada itu.

Langkah berikutnya adalah untuk membandingkan cdengan EOF. Sebagai EOFadalah int, cakan dikonversi ke intjuga, melestarikan nilai yang disimpan dalam c. Jika cbisa menyimpan nilai EOF, maka perbandingan akan berhasil, tetapi jika tidakc bisa menyimpan nilai, maka perbandingan akan gagal, karena telah terjadi kehilangan informasi yang tidak dapat dipulihkan saat mengonversi untuk mengetik .EOFchar

Tampaknya kompiler Anda memilih untuk membuat charjenis ditandatangani dan nilai EOFcukup kecil untuk masuk char. Jika chartidak ditandatangani (atau jika Anda telah menggunakan unsigned char), pengujian Anda akan gagal, karena unsigned chartidak dapat menyimpan nilai EOF.


Perhatikan juga bahwa ada masalah kedua dengan kode Anda. Karena EOFbukan karakter itu sendiri, tetapi Anda memaksanya menjadi suatu chartipe, sangat mungkin ada karakter di luar sana yang disalahartikan sebagai EOFdan untuk separuh karakter yang mungkin tidak ditentukan apakah karakter tersebut akan diproses dengan benar.

Bart van Ingen Schenau
sumber
Memaksa untuk mengetikkan charnilai di luar rentang CHAR_MIN.. CHAR_MAXakan diperlukan untuk menghasilkan nilai yang ditentukan-implementasi, menghasilkan pola bit yang didefinisikan oleh implementasi sebagai representasi trap, atau menaikkan sinyal yang ditentukan implementasi. Dalam kebanyakan kasus, implementasi harus melalui banyak pekerjaan ekstra untuk melakukan apa pun selain pengurangan dua-pelengkap. Jika orang-orang di Komite Standar berlangganan gagasan bahwa penyusun harus didorong untuk menerapkan perilaku yang konsisten dengan kebanyakan penyusun lain dengan tidak adanya alasan untuk melakukan sebaliknya ...
supercat
... Saya akan menganggap paksaan seperti itu dapat diandalkan (tidak untuk mengatakan bahwa kode tidak boleh mendokumentasikan niatnya, tapi itu (signed char)xharus dianggap lebih jelas dan sama amannya ((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1).) Seperti itu, saya tidak melihat kemungkinan adanya kompiler yang menerapkan perilaku lain yang sesuai dengan standar saat ini; salah satu bahayanya adalah bahwa Standar tersebut dapat diubah untuk menghentikan perilaku demi kepentingan "optimisasi".
supercat
@supercat: Standar ditulis sedemikian rupa sehingga tidak ada kompiler yang harus menghasilkan kode yang memiliki perilaku yang tidak didukung oleh prosesor yang ditargetkan. Sebagian besar perilaku tidak terdefinisi ada karena (pada saat penulisan standar) tidak semua prosesor bertindak secara konsisten. Dengan kompiler yang semakin matang, penulis kompiler mulai mengambil manfaat dari perilaku yang tidak terdefinisi untuk membuat optimisasi yang lebih agresif.
Bart van Ingen Schenau
Secara historis, maksud dari Standar sebagian besar seperti yang Anda gambarkan, meskipun Standar menggambarkan beberapa perilaku dalam detail yang cukup untuk memerlukan kompiler untuk beberapa platform umum untuk menghasilkan kode lebih banyak daripada yang diperlukan di bawah spesifikasi yang lebih longgar. Jenis paksaan di int i=129; signed char c=i;adalah salah satu perilaku tersebut. Relatif sedikit prosesor yang memiliki instruksi yang csetara idengan -127 hingga +127 dan akan menghasilkan pemetaan nilai-nilai lain yang konsisten ipada kisaran -128 hingga +127 yang berbeda dari reduksi dua komplemen, atau. ..
supercat
... akan secara konsisten meningkatkan sinyal dalam kasus seperti itu. Karena Standar mensyaratkan bahwa implementasi baik menghasilkan pemetaan yang konsisten atau secara konsisten menaikkan sinyal, satu-satunya platform di mana Standar akan meninggalkan ruang untuk sesuatu selain pengurangan dua komplemen akan hal-hal seperti DSP dengan perangkat keras aritmatika jenuh. Adapun dasar historis untuk Perilaku Tidak Terdefinisi, saya akan mengatakan bahwa masalahnya bukan hanya dengan platform perangkat keras. Bahkan pada platform di mana overflow akan berperilaku dengan cara yang sangat konsisten, mungkin berguna untuk memiliki perangkap kompiler itu ...
supercat