Problem with EOF when using pipes and stdin

Y

Yandos

Hello all,

I have maybe a trivial question, but I cannot think out what is wrong :(
How do i detect EOF correctly when i read from stdin? Am I doing it
wrong?

<pipetest.c>
#include <stdio.h>
int main(void) {
char ch;
while (!feof(stdin)) { // <-- EOF appears to be true when character 0x1A is on stdin
ch=getchar(); // <-- variable ch has value of 0xFF when 0x1A was on stdin
putchar(ch);
}
return(0);
}

<256.tmp>
contains values from 0 to 255

I compiled and run from cmd prompt: pipetest.exe < 256.tmp > out.tmp

<out.tmp>
00000000 00 01 02 03 04 05 06 07 08 09 0D 0A 0B 0C 0E 0F
00000010 10 11 12 13 14 15 16 17 18 19 FF

Why the program ended on 0x1A character and outputted FF instead?

How do I correctly write program which can be used with pipes? I use
free borland turbo c++ 1.01 compiler on windows xp.

Thanks anyone for kind help,
Y.
 
Y

Yandos

Now I know I need to read and write files in binary mode. I know how to open file on disk in binary mode,
but how do i open stdin and stdout in binary? (AFAIK these files are yet opened)

Thanks anyone for kind help,
Yandos
 
G

Guest

How do i detect EOF correctly when i read from stdin? Am I doing it
wrong?

As apparent from another post of yours, I think you are learning C, not C++.
You may find better answers at comp.lang.c and/or alt.comp.lang.learn.c-c++
<pipetest.c>
#include <stdio.h>
int main(void) {
char ch;
while (!feof(stdin)) { // <-- EOF appears to be true when
character 0x1A is on stdin
ch=getchar(); // <-- variable ch has value of 0xFF when
0x1A was on stdin
putchar(ch);

getchar actually returns int. What you are doing is truncating that value
and outputting something else.
}
return(0);
}

<256.tmp>
contains values from 0 to 255

I compiled and run from cmd prompt: pipetest.exe < 256.tmp > out.tmp
<out.tmp>
00000000 00 01 02 03 04 05 06 07 08 09 0D 0A 0B 0C 0E 0F
00000010 10 11 12 13 14 15 16 17 18 19 FF

Why the program ended on 0x1A character and outputted FF instead?

I don't know... :(
How do I correctly write program which can be used with pipes? I use
free borland turbo c++ 1.01 compiler on windows xp.

You are using a compiler that was released in 1991! :)

You should consider getting a more modern compiler. For the Windows
environment; there is a free one from Microsoft, a free one from Borland,
and a very nice free development environment named Dev-C++ that which uses
gcc as the compiler.

Ali
 
A

Artie Gold

Yandos said:
Hello all,

I have maybe a trivial question, but I cannot think out what is wrong :(
How do i detect EOF correctly when i read from stdin? Am I doing it
wrong?

<pipetest.c>
#include <stdio.h>
int main(void) {
char ch;
Bzzzt. make that:
int ch; /* since EOF, by definition is a value *not* representable
by char (this is why getchar returns int) */
while (!feof(stdin)) { // <-- EOF appears to be true when character 0x1A is on stdin

Bzzzt. feof() will return true only *after* a read attempt returns EOF
(this ain't Pascal).
ch=getchar(); // <-- variable ch has value of 0xFF when 0x1A was on stdin
putchar(ch);
}
return(0);
}

<256.tmp>
contains values from 0 to 255

I compiled and run from cmd prompt: pipetest.exe < 256.tmp > out.tmp

<out.tmp>
00000000 00 01 02 03 04 05 06 07 08 09 0D 0A 0B 0C 0E 0F
00000010 10 11 12 13 14 15 16 17 18 19 FF

Why the program ended on 0x1A character and outputted FF instead?

How do I correctly write program which can be used with pipes? I use
free borland turbo c++ 1.01 compiler on windows xp.

*That* is off topic here; pipes are not part of standard C++.
I recommend that you see the C FAQ, as these are functions (getchar(),
etc) from the C library inherited into C++.

HTH,
--ag
 
R

Roberto Waltman

Hello all,

I have maybe a trivial question, but I cannot think out what is wrong :(
How do i detect EOF correctly when i read from stdin? Am I doing it
wrong?

<pipetest.c>
#include <stdio.h>
int main(void) {
char ch;
while (!feof(stdin)) { // <-- EOF appears to be true when character 0x1A is on stdin
ch=getchar(); // <-- variable ch has value of 0xFF when 0x1A was on stdin
putchar(ch);
}
return(0);
}

<256.tmp>
contains values from 0 to 255

I compiled and run from cmd prompt: pipetest.exe < 256.tmp > out.tmp

<out.tmp>
00000000 00 01 02 03 04 05 06 07 08 09 0D 0A 0B 0C 0E 0F
00000010 10 11 12 13 14 15 16 17 18 19 FF

Why the program ended on 0x1A character and outputted FF instead?

How do I correctly write program which can be used with pipes? I use
free borland turbo c++ 1.01 compiler on windows xp.

Thanks anyone for kind help,
Y.

First of all, both questions you posted were centered on the
(mis)behavior of a C, (not C++,) program. If you have C questions
you'll get a better responses and more patience in a C related group.

Now to your question: Borland's Turbo C++ 1.0 is an old compiler,
(I believe I bought it in 1990?) written at a time were compatibility
with MS-DOS (plain DOS, not Windows) was important. Many details of
the run time library ensure compatibility with data files created by
other DOS programs, many of which tried to be compatible with files
created under DOS, CPM-86 and CPM-80.

All these last three operating systems use a CONTROL-Z character
(0x1A) as an end-of-file marker in text files. The (historic) reason
being that CPM-80 kept track of file sizes only as the number of 128
byte blocks. To know exactly where a text file ended in the last
block, the convention of using CTRL-Z (a non-printable character) was
established.

So your program stops reading when it receives an indication it
reached the end of file. The 0xFF following it is an error code
supplied when you try to read from a file beyond the logical
end-of-file.

Also note that before reaching CTRL-Z, the newline char (0x0A) was
expanded into carriage return - newline (0x0D 0x0A) and that the
carriage return following it was discarded. Opening the file/pipe in
binary mode would correct all these problems

I am sure there must be a way of modifying your program to tell BC++
1.0 to use binary mode, but it would be a waste of time. You can get
other (more modern) free compilers, and your time would be better
spent learning to do this on LCC-Win32, Digital Mars C/C++, GCC, or
even Microsoft compilers. (They are free, not Visual Studio, but the
underlying compilers.)
Roberto Waltman

[ Please reply to the group, ]
[ return address is invalid. ]
 
Y

Yandos

First of all, both questions you posted were centered on the
(mis)behavior of a C, (not C++,) program. If you have C questions
you'll get a better responses and more patience in a C related group.

Right. I don't know what's the difference :( I thought i have c++ compiler, so best place is to ask here :)
Simple and stupid, sorry :( I will read more about that difference and try to figure right group next time.
Now to your question: Borland's Turbo C++ 1.0 is an old compiler,
(I believe I bought it in 1990?) written at a time were compatibility
with MS-DOS (plain DOS, not Windows) was important. Many details of
the run time library ensure compatibility with data files created by
other DOS programs, many of which tried to be compatible with files
created under DOS, CPM-86 and CPM-80.

All these last three operating systems use a CONTROL-Z character
(0x1A) as an end-of-file marker in text files. The (historic) reason
being that CPM-80 kept track of file sizes only as the number of 128
byte blocks. To know exactly where a text file ended in the last
block, the convention of using CTRL-Z (a non-printable character) was
established.

So your program stops reading when it receives an indication it
reached the end of file. The 0xFF following it is an error code
supplied when you try to read from a file beyond the logical
end-of-file.

Also note that before reaching CTRL-Z, the newline char (0x0A) was
expanded into carriage return - newline (0x0D 0x0A) and that the
carriage return following it was discarded. Opening the file/pipe in
binary mode would correct all these problems

Damn, how do you know all this? :) This is very interesting. Now I unerstand...
I am sure there must be a way of modifying your program to tell BC++
1.0 to use binary mode, but it would be a waste of time. You can get
other (more modern) free compilers, and your time would be better
spent learning to do this on LCC-Win32, Digital Mars C/C++, GCC, or
even Microsoft compilers. (They are free, not Visual Studio, but the
underlying compilers.)
Roberto Waltman

[ Please reply to the group, ]
[ return address is invalid. ]

Roberto, thank you again for very useful reply. I glad you realized I'm absoulte newbie and handled me
with care :) I have learned a lot from your words. The reason why i'm starting with old borland compiler
is that i knew it is free and i don't yet know the syntax of c and compiler is helping me a lot to correct
"grammar" :) (I have learned pascal before) One big thank you! ;)

Y.
 
Y

Yandos

As apparent from another post of yours, I think you are learning C,
not C++. You may find better answers at comp.lang.c and/or
alt.comp.lang.learn.c-c++

Right, thank you for hint. I will read more about the difference and next time try to figure the correct
group ;)
getchar actually returns int. What you are doing is truncating that
value and outputting something else.

IC, thanks. Anyway, the result is still the same, no matter if i use int or char. But I will keep that in mind.
You are using a compiler that was released in 1991! :)

You should consider getting a more modern compiler. For the Windows
environment; there is a free one from Microsoft, a free one from
Borland, and a very nice free development environment named Dev-C++
that which uses gcc as the compiler.

Ali

Thank you again for hint, i will try it. I have started with borland c++ because i have learned turbo
pascal before, and knew that borland had released c++ 1.01 for free use - and i needed some "gui"
because i need a lot of help with syntax.

Y.
 
Y

Yandos

Bzzzt. make that:
int ch; /* since EOF, by definition is a value *not*
representable
by char (this is why getchar returns int) */

IC, thanks :) But on the result there's no difference, but i will now be more careful on data types.
Pascal would have warned me...
Bzzzt. feof() will return true only *after* a read attempt returns EOF
(this ain't Pascal).

Not really. Also when 0x1A is received, because stdin is opened in text mode by default in turbo c++
1.01 because of compatibility reasons (Roberto right explained that in different thread)
*That* is off topic here; pipes are not part of standard C++.

IC, sorry.
I recommend that you see the C FAQ, as these are functions (getchar(),
etc) from the C library inherited into C++.

HTH,
--ag

Thank you for help, I have a lot to learn yet :) And apologies for off topic...
Y.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,818
Latest member
Brigette36

Latest Threads

Top