Gönderen Konu: while(!feof)  (Okunma sayısı 6263 defa)

0 Üye ve 1 Ziyaretçi konuyu incelemekte.

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
while(!feof)
« : 02 Kasım 2018, 20:50:38 »
cc65'le uğraştığım son mini projemde CBM SEQ dosyasından veri çekmek için cc65 e-mail grubunda denk geldiğim kodlardan devşirdiğim aşağıdaki fonksiyonu kullanıyorum. Ancak sonradan öğrendim ki while( !feof(ptr) ) kullanımı caiz değilmiş. Aşağıdaki gibi didaktik açıklamalar söz konusu.

EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.

Okuma sırasında arada hata olursa kodun patlayacağından bahsedilmiş.  while(!feof(ptr) && !ferror(ptr)) şeklindeki kullanım bunu çözmez mi? Yoksa multitasking sistemlerde başka bir programın dosyaya ilave yapması gibi durumlar mı sorun oluşturuyor?

Kod: [Seç]
void read_tree(uchar * id)
{
uchar *buffer;
uchar *file_name;
FILE *file;
uchar i;

buffer = malloc(1 * sizeof(uchar));
file_name = malloc(8 * sizeof(uchar));

// Dosya ismini hesapla
itoa(id, buffer, 2);
strcpy(file_name,"tdat");
strcat(file_name,buffer);

cprintf("\n\rVeri dosyasi aciliyor...");
_filetype = 's';
if(file = fopen(file_name, "r"))
{
cprintf("\n\rVeriler aliniyor...");
i=0;
while(!feof(file))
{
fread(&node[i], sizeof(struct Node), 1, file);
i++;
}
fclose(file);
cprintf("\n\rOk.");
}
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı eins

  • RAAT
  • Retroman
  • *
  • İleti: 29
Ynt: while(!feof)
« Yanıtla #1 : 02 Kasım 2018, 21:32:01 »
Selamlar,

Benim bildiğim eof oluşması için read veya write yapılmış olması gerekiyor. Yani yeni açılan bir dosyada read veya write yapmadan dosya boş olsa bile eof oluşmuyor. Bu sebeple while içinde değil, işlem sonrasında bu kontrolü yapak doğru diye biliyorum.

Örneğin pascal olsa,

repeat
...
until eof

şeklinde yazardım.

NOT: Ben deliMawi yada ilker bu arada ...

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: while(!feof)
« Yanıtla #2 : 02 Kasım 2018, 21:38:44 »
C64 özelinde bu şekilde gayet çalışıyor aslında. Belki dosyanın boş olduğu durumda problem yaratabilir bir de okuma sırasında disket sürücüyü kapatırsan veya network kablosunu çekersen sonsuz döngüye girer denilmiş. Ancak okuma sırasında disket sürücü kapatıldığında veya disket çıkartıldığında programın kilitlenmesi bana gayet makul göründü.

// Ayrıca sen zaten foruma kayıtlı değil miydin? Kullanıcı kaydıyla ilgili bir sorun mu oluştu?
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı eins

  • RAAT
  • Retroman
  • *
  • İleti: 29
Ynt: while(!feof)
« Yanıtla #3 : 02 Kasım 2018, 22:07:26 »
Uzun zamandır girmediğim için kaydım uçmuş.

Bu arada zamanında kullandığım gerçek nickim zaten eins idi. Ancak 5-6 sene önce, retro forumlara üye olmaya başladığımda, özellikle yabancı birçok foruma eins niki ile kayıt olamadım, bende o dönemde alternatif nick olarak deliMawi yi kullanmaya başlamıştım. Şimdi fırsat bu fırsat, tekrar üye olurken eins ile kayıt oldum...

Yukarıda ki konuya ilişkin olarak, çalışıp çalışmamasından öte, gerçek anlamda eof durumunun oluşabilmesi için bir i/o işlemi yapılması gerekliliği var. Benim burada mantık olarak yanlış olabileceğini düşündüğüm tek nokta, while döngüsünde kontrolün işlemden önce yapılıyor olması.

EK NOT: While loop öncesinde bir read ile başlanmış olsa bence caiz olurdu...

Çevrimdışı eins

  • RAAT
  • Retroman
  • *
  • İleti: 29
Ynt: while(!feof)
« Yanıtla #4 : 02 Kasım 2018, 22:13:34 »
Bir ek not daha.

Yukarıda ki örnek kodda mesela, dosyada ki son veriyi de okudun. Ama son veri okununca henüz eof oluşmadı. Dolayısı ile while bir kez daha girdi döngüye. Read yaptın ve eof oluştu. Ama sen bu arada çoktan bir veri okudğunu düşünüp bunu işledin... Ama o okumaya çalıştığın son veri yoktu dosyada. Anlatabildim umarım.

Şu daha doğru:

Kod: [Seç]
i=0;
fread(&node[i], sizeof(struct Node), 1, file);
while(!feof(file))
{
i++;
fread(&node[i], sizeof(struct Node), 1, file);
}

Şöyle yazınca da daha rtistik oluyor: :)
Kod: [Seç]
i=0;
fread(&node[i], sizeof(struct Node), 1, file);
while(!feof(file))
{
fread(&node[++i], sizeof(struct Node), 1, file);
}

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: while(!feof)
« Yanıtla #5 : 02 Kasım 2018, 22:27:12 »
Öneri #1:

Kod: [Seç]
do {
   ...
} while (condition);

Öneri #2:

Kod: [Seç]
while (true) {
   ...
   if (condition) break;
}

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: while(!feof)
« Yanıtla #6 : 02 Kasım 2018, 22:38:52 »
Bir yandan matahari'nin minimalist cevabı üzerine düşünürken, diğer taraftan da sana cevap vermeden duramadım.

İlk mesajında bahsettiğin read/write yapmadan eof oluşmuyor olması benim durumumda problem olmuyor. Zira okuma yapmadan çağırdığım ilk foef() True döndürüyor.

İkinci söylediğin fazladan bir kayıt okuma konusunda haklısın ancak kafamı kurcalayan dosyaya kullandığım dizinin boyutu kadar veri yazmıştım. Geri okurken fazla veri okuduğundan çakılması gerekmez miydi? Sanırım tamamen şansa çalıştı. Konuyu fazla uzatmadan şu koşulu sona alayım.



 
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı eins

  • RAAT
  • Retroman
  • *
  • İleti: 29
Ynt: while(!feof)
« Yanıtla #7 : 02 Kasım 2018, 23:00:03 »
Çakılması gerekmez. node değişkeninden sonra ne olduğuna bağlı hafızada. Eğer tam dosya boyutu kadar ise node'a ayrılan bölüm, muhtemelen bir sonraki değişken için ayrılan yere birşeyler yazıyorsun...

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: while(!feof)
« Yanıtla #8 : 02 Kasım 2018, 23:06:05 »
Kodu where(!feof())'nin günah olduğuna inanarak okuyabiliyorsan oku anlamına gelecek şekilde aşağıdaki gibi değiştirmiştim. Bu da sorunsuz çalışıyor.

Kod: [Seç]
while(fread(&node[i], sizeof(struct Node), 1, file))
{
gotox(wherex()-3);
cprintf("%%%2d",(i++));
}
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı eins

  • RAAT
  • Retroman
  • *
  • İleti: 29
Ynt: while(!feof)
« Yanıtla #9 : 03 Kasım 2018, 00:08:28 »
Evet, zaten doğru mantık da bu. Okuyabiliyorsan oku! Ha okuyamadıysan, yani sonuç 0 döndüyse iki seçenek kalmıştır. Ya feof, yada ferror... Bunu da gerekirse kontrol edip duruma göre davranabilirsin...

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: while(!feof)
« Yanıtla #10 : 03 Kasım 2018, 03:28:04 »
Cevaplar için teşekkürler. Sonuçta dosyanın başına kayıt sayısını da ekleyerek kodu aşağıdaki hale getirdim.

Kod: [Seç]
fread(&num_of_nodes, sizeof(uchar), 1, file);
for(i=0; i<num_of_nodes; i++)
{
fread(&node[i], sizeof(struct Node), 1, file);
gotox(wherex()-3);
cprintf("%%%2d",(100*(i+1)/num_of_nodes));
if(feof(file)) break;
}
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı Alpyre

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 106
Ynt: while(!feof)
« Yanıtla #11 : 03 Kasım 2018, 12:51:12 »
O değil de gördüğüm kadarıyla read_tree() fonksiyonun (oradaki itoa bildiğimiz standard library itoa'sı ise) bildiğin memory trashing yapıyor sanki. Şöyle ki:

fonksiyonun bir uchar * id alıyor. Pointer olduğuna göre bunun değeri bir memory address tutuyor C64 olduğuna göre 16 bit bir adres olsa gerek.
sonra bir buffer tahsis etmişsin:
Kod: [Seç]
uchar *buffer;
buffer = malloc(1 * sizeof(uchar));
uchar (bildiğimiz unsigned char ise bu) sizeof(uchar) zaten 1 byte. 1 x 1 = 1 byte'lık buffer allocate etmiş oldun.

ama sonra şu var:
Kod: [Seç]
itoa(id, buffer, 2);
bu fonksiyon id'nin değerini bir binary string'e çevirip buffer'a yazar (son argümana 2 demişsin çünkü). Şimdi bu id memory adress olduğuna göre büyükçe bir sayı. E bunu bir de binary'ye çevirdin, (bir değer sallıyorum) diyelim oldu sana "1111 1010 0100" gibi bir string. itoa() bunu yazdı buffer'a. Ama buffer 1 byte'cık (salladığım sıralıda var 12 karakter -  yani 12 byte - 1 byte'ı buffer'a yazdı ama ardından gelen 11 byte'ı trash etti).

Yanlışım varsa söyleyin lütfen. :)

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: while(!feof)
« Yanıtla #12 : 03 Kasım 2018, 17:38:07 »
@Alpyre;

Bahsettiğin probleme rastlamadım. Tahminim compiler bunu kendisi hallediyor ancak "Converting pointer to integer without a cast" şeklinde bir warning veriyordu. Bu uyarıyı iki yerde daha alıyordum. Çözümünü sonraya bırakmıştım.

Senin uyarından sonra biraz araştırdım ve kodu itoa((uchar)id, buffer, 10) şeklinde değiştirerek warning'den kurtuldum.





Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı Alpyre

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 106
Ynt: while(!feof)
« Yanıtla #13 : 03 Kasım 2018, 17:46:12 »
@Alpyre;
Bahsettiğin probleme rastlamadım. Tahminim compiler bunu kendisi hallediyor ancak "Converting pointer to integer without a cast" şeklinde bir warning veriyordu. Bu uyarıyı iki yerde daha alıyordum. Çözümünü sonraya bırakmıştım.

Senin uyarından sonra biraz araştırdım ve kodu itoa((uchar)id, buffer, 10) şeklinde değiştirerek warning'den kurtuldum.

Şimdi warning'den kurtulman güzel de... hala aynı memory trashing olayı söz konusu.
Kod'un o kısmı tam olarak ne iş görüyor? Sanki orada itoa() değil de atoi() kullanılması gerekiyor gibi geliyor bana ama...

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: while(!feof)
« Yanıtla #14 : 04 Kasım 2018, 13:43:41 »
integer'ı daha sonra dosya adına eklemek üzere char'a döndürüyorum.

atoi() bunun tam tersini yapmıyor mu?
Gosub ile gidilen yerden goto ile dönen adam