strange behavior with C - Minix

This is a discussion on strange behavior with C - Minix ; comp.os.minix strange behavior with C The code below was intended to display keys from the keyboard. However, printf causes unexpected behavior. Using the write function rather than printf yields the following for entry of the keys asdq: aX sX dX ...

+ Reply to Thread
Results 1 to 17 of 17

Thread: strange behavior with C

  1. strange behavior with C

    comp.os.minix
    strange behavior with C

    The code below was intended to display keys from the keyboard. However, printf
    causes unexpected behavior. Using the write function rather than printf yields
    the following for entry of the keys asdq:

    aX sX dX q

    with printf() instead of write() though, the result is:

    asdgX X X

    This looks like a recursive call was placed in printf's place. Or the system,
    or maybe tty, is storing the results then passing them on an end of
    process/user signal?

    Isolating printf as a cause is possibly not valid. If memory serves correctly,
    other functions in the c library resulted in the same delayed printing.

    If anyone has an explanation or a possibility, please mention it.

    Hul

    ps: the same results occur without the keyraw/keyreset functions but with the
    key included , so that's ruled out as a cause.

    int main()
    {
    int x;
    char c;
    keyraw(); /* change tty to "raw" mode */
    for(;
    {
    while((x = read(0, &c, 1)) < 1)
    ;
    if(c < 0x20)
    c += 0x20;
    write(1, &c, 1);
    if(c == 'q')
    break;
    /* printf("X ", x); */
    write(1, "X ", 3);
    }
    keyreset(); /* return tty to previous mode */
    }

  2. Re: strange behavior with C

    Hul Tytus wrote:
    > comp.os.minix
    > strange behavior with C


    > The code below was intended to display keys from the keyboard. However, printf
    > causes unexpected behavior. Using the write function rather than printf yields
    > the following for entry of the keys asdq:


    > aX sX dX q


    > with printf() instead of write() though, the result is:


    > asdgX X X




    It looks like printf() uses a buffer while write() doesn't, and that
    calling write(1, &c,1) does not cause the buffer of printf() to be flushed
    to standard output. That is why first all output of write(1, &c, 1)
    appears on the output and, when the program terminates, the accumulated
    buffer of printf() is printed after that.


    --
    Jens de Smit
    Student Computer Science | Vrije Universiteit Amsterdam
    jfdsmit@few.vu.nl | http://www.few.vu.nl/~jfdsmit

  3. Re: strange behavior with C

    The results do look as if printf is delaying the output in a buffer, as
    you say. Do you have any idea why printf would use a delaying action?
    Waiting for a carridge return?

    Hul

    Smit de JF wrote:
    > Hul Tytus wrote:
    > > comp.os.minix
    > > strange behavior with C


    > > The code below was intended to display keys from the keyboard. However, printf
    > > causes unexpected behavior. Using the write function rather than printf yields
    > > the following for entry of the keys asdq:


    > > aX sX dX q


    > > with printf() instead of write() though, the result is:


    > > asdgX X X


    >


    > It looks like printf() uses a buffer while write() doesn't, and that
    > calling write(1, &c,1) does not cause the buffer of printf() to be flushed
    > to standard output. That is why first all output of write(1, &c, 1)
    > appears on the output and, when the program terminates, the accumulated
    > buffer of printf() is printed after that.



    > --
    > Jens de Smit
    > Student Computer Science | Vrije Universiteit Amsterdam
    > jfdsmit@few.vu.nl | http://www.few.vu.nl/~jfdsmit


  4. Re: strange behavior with C

    > Isolating printf as a cause is possibly not valid. If memory serves
    > correctly, other functions in the c library resulted in the same
    > delayed printing.
    >
    > If anyone has an explanation or a possibility, please mention it.


    The stream functions in stdio.h are meant to perform buffered input and
    output, probably to increase performance. Therefore stream I/O should
    not be mixed with low-level I/O.

    Unfortunately the Minix man pages do not seem to mention this
    explicitly, but the Linux man page for putc (which is used to implement
    printf and friends) words it like this:


    It is not advisable to mix calls to output functions from the stdio
    library with low - level calls to write() for the file descriptor
    associated with the same output stream; the results will be undefined
    and very probably not what you want.




  5. Re: strange behavior with C

    > > Isolating printf as a cause is possibly not valid. If memory serves
    > > correctly, other functions in the c library resulted in the same
    > > delayed printing.
    > >
    > > If anyone has an explanation or a possibility, please mention it.

    >
    > The stream functions in stdio.h are meant to perform buffered input
    > and output, probably to increase performance. Therefore stream I/O
    > should not be mixed with low-level I/O.


    For completeness, this is the implementation for putc, which is used to
    implement printf:

    #define putc(c, p) (--(p)->_count >= 0 ? \
    (int) (*(p)->_ptr++ = (c)) : \
    __flushbuf((c),(p)))

    You will find this definition in include/stdio.h.

    You can clearly see here that the only "special" thing stream-based I/O
    does is buffering. Only when the buffer is filled will it be written to
    the low level file descriptor.

  6. Re: strange behavior with C

    dr@kbrx.com wrote:
    > The results do look as if printf is delaying the output in a buffer, as
    > you say. Do you have any idea why printf would use a delaying action?
    > Waiting for a carridge return?


    Writing to a terminal (or tty) is a costly operation in terms of
    performance, while writing to a buffer is cheap. Buffering output and
    writing it to a terminal once in a while instead of every singel
    character immediately therefore increases performance.

    --
    Jens de Smit
    Student Computer Science | Vrije Universiteit Amsterdam
    jfdsmit@few.vu.nl | http://www.few.vu.nl/~jfdsmit

  7. Re: strange behavior with C

    Erik - thanks for the location of putc and it's implication. However, if
    the code that was previously posted is rewritten with printf & getchar in
    place of write & read, the result is the same as occurs with w & r.

    In other words, the c library version and the system version both produce
    the same output. The error only occurs when they are mixed. In
    the c library something, possibly in the printf code, trigers the
    flushbuffer function.

    Hul

    Erik van der Kouwe wrote:
    > > > Isolating printf as a cause is possibly not valid. If memory serves
    > > > correctly, other functions in the c library resulted in the same
    > > > delayed printing.
    > > >
    > > > If anyone has an explanation or a possibility, please mention it.

    > >
    > > The stream functions in stdio.h are meant to perform buffered input
    > > and output, probably to increase performance. Therefore stream I/O
    > > should not be mixed with low-level I/O.


    > For completeness, this is the implementation for putc, which is used to
    > implement printf:


    > #define putc(c, p) (--(p)->_count >= 0 ? \
    > (int) (*(p)->_ptr++ = (c)) : \
    > __flushbuf((c),(p)))


    > You will find this definition in include/stdio.h.


    > You can clearly see here that the only "special" thing stream-based I/O
    > does is buffering. Only when the buffer is filled will it be written to
    > the low level file descriptor.


  8. Re: strange behavior with C


    dr@kbrx.com writes:

    > Erik - thanks for the location of putc and it's implication. However, if
    > the code that was previously posted is rewritten with printf & getchar in
    > place of write & read, the result is the same as occurs with w & r.
    >
    > In other words, the c library version and the system version both produce
    > the same output. The error only occurs when they are mixed. In
    > the c library something, possibly in the printf code, trigers the
    > flushbuffer function.



    See setbuf(3). Buffering can be set to unbuffered, line buffered and
    fully buffered. In 'line buffered' mode the buffer will be flushed as
    soon as a carriage return '\n' has been written into the buffer. This
    is the default mode.

    I also don't agree (IMHO, YMMV) that mixing the calls to the system
    (unbuffered) and the libc version (buffered) is generally
    undefined. One can always call fflush() on the FILE* (the buffered
    libc file object) to flush the user space buffer and the continue with
    using the file descriptor in a system call. I admit that there might
    be (tiny ...) problem with error conditions: If you use a system call,
    the FILE* object of course will not get to know of the error/EOF
    condition and the next write/read will have interesting results.

    But of course mixing stdio and unix io is usually not necessary with
    the one exceaption of producing a FILE* from a unix filedescriptor
    with fdopen(), which is useful to use stdio on sockets.

    Regards -- Markus




  9. Re: strange behavior with C

    Markus - setbuf() worked well. Many thanks. I'll keep fflush() in mind
    also, just in case.

    Hul


    > See setbuf(3). Buffering can be set to unbuffered, line buffered and
    > fully buffered. In 'line buffered' mode the buffer will be flushed as
    > soon as a carriage return '\n' has been written into the buffer. This
    > is the default mode.


    > I also don't agree (IMHO, YMMV) that mixing the calls to the system
    > (unbuffered) and the libc version (buffered) is generally
    > undefined. One can always call fflush() on the FILE* (the buffered
    > libc file object) to flush the user space buffer and the continue with
    > using the file descriptor in a system call. I admit that there might
    > be (tiny ...) problem with error conditions: If you use a system call,
    > the FILE* object of course will not get to know of the error/EOF
    > condition and the next write/read will have interesting results.


    > But of course mixing stdio and unix io is usually not necessary with
    > the one exceaption of producing a FILE* from a unix filedescriptor
    > with fdopen(), which is useful to use stdio on sockets.


    > Regards -- Markus





  10. Re: strange behavior with C

    All,

    > The results do look as if printf is delaying the output in a buffer, as
    > you say. Do you have any idea why printf would use a delaying action?
    > Waiting for a carridge return?


    No, that's standard operating procedure for stdio. Streams can be
    buffered (size BUFSIZ), line buffered (flush on newline), or
    unbuffered. By default, if the output is a terminal, stdout is line
    buffered, otherwise it's buffered. By default, stderr is unbuffered.

    You can force a flush by calling fflush(stdout).

    =Ben



  11. Re: strange behavior with C

    In article ,
    Ben Gras wrote:
    >
    >You can force a flush by calling fflush(stdout).


    Also useful is fflush(NULL), that flushes all output streams.
    Especially handy just before a fork() if you intend to use stdio
    streams in the child process. (Because the state of unflushed streams
    is copied both to parent and child, so if you're not careful they'll be
    flushed twice, both in parent and child.) Also note the difference
    between exit() and _exit() in this context. Always use _exit() in a
    child process if you don't intend to use stdio streams there.

    Learned all of that the hard way, of course. Sometimes with a program
    working perfectly on the command line (stdout line-buffered), but making
    a mess if running in the background (stdout fully buffered), so you
    don't immediately notice while testing.
    --
    Kees J. Bot, Systems Programmer, Sciences dept., Vrije Universiteit Amsterdam

  12. Re: strange behavior with C

    In article ,
    Markus E Leypold
    wrote:
    >I also don't agree (IMHO, YMMV) that mixing the calls to the system
    >(unbuffered) and the libc version (buffered) is generally
    >undefined.


    It is not undefined according to POSIX. The way to mix read/write calls
    with operations on stdio streams is discussion in a section called
    'Interaction of File Descriptors and Standard I/O Streams' in the
    System Interfaces / General Information part of the Open Group Base
    Specifications.


    --
    That was it. Done. The faulty Monk was turned out into the desert where it
    could believe what it liked, including the idea that it had been hard done
    by. It was allowed to keep its horse, since horses were so cheap to make.
    -- Douglas Adams in Dirk Gently's Holistic Detective Agency

  13. Re: strange behavior with C

    Thanks again to all of you with suggestions.

    Hul

    Kees J Bot wrote:
    > In article ,
    > Ben Gras wrote:
    > >
    > >You can force a flush by calling fflush(stdout).


    > Also useful is fflush(NULL), that flushes all output streams.
    > Especially handy just before a fork() if you intend to use stdio
    > streams in the child process. (Because the state of unflushed streams
    > is copied both to parent and child, so if you're not careful they'll be
    > flushed twice, both in parent and child.) Also note the difference
    > between exit() and _exit() in this context. Always use _exit() in a
    > child process if you don't intend to use stdio streams there.


    > Learned all of that the hard way, of course. Sometimes with a program
    > working perfectly on the command line (stdout line-buffered), but making
    > a mess if running in the background (stdout fully buffered), so you
    > don't immediately notice while testing.
    > --
    > Kees J. Bot, Systems Programmer, Sciences dept., Vrije Universiteit Amsterdam


  14. Re: strange behavior with C


    dr@kbrx.com writes:

    > Markus - setbuf() worked well. Many thanks. I'll keep fflush() in mind
    > also, just in case.
    >
    > Hul


    But mind: As others have already written, unbuffered I/O is
    expensive. So the general rule -- not to mix stdio with unix i/o
    except you really need to do and know what you're doing -- is a good
    rule most of the time.

    Regards -- Markus


  15. Re: strange behavior with C

    Markus: By "unbuffered I/O is expensive" do you mean that running down
    the input or output channel for each single byte takes time? I'm assuming
    this is your meaning, but always best to verify.

    Hul

    Markus E Leypold wrote:

    > dr@kbrx.com writes:


    > > Markus - setbuf() worked well. Many thanks. I'll keep fflush() in mind
    > > also, just in case.
    > >
    > > Hul


    > But mind: As others have already written, unbuffered I/O is
    > expensive. So the general rule -- not to mix stdio with unix i/o
    > except you really need to do and know what you're doing -- is a good
    > rule most of the time.


    > Regards -- Markus



  16. Re: strange behavior with C

    dr@kbrx.com wrote:
    > Markus: By "unbuffered I/O is expensive" do you mean that running down
    > the input or output channel for each single byte takes time? I'm assuming
    > this is your meaning, but always best to verify.


    When writing character(s) to a screen, this involves operations to write
    to the framebuffer (or character buffer in text mode). Either way, a
    driver call has to be made to the terminal driver, which involves wrapping
    the data in a message, sending the message thorugh the kernel, unwrapping
    the message at the driver, and performing IOCTL operations to write the
    characters to the display device. In short: writing characters to a device
    incurs overhead. Writing characters to a memory area is much cheaper: no
    overhead and also no context switching. When using buffered I/O with a
    buffer size of, say, 40 characters, then all this overhead only occurs
    once every 40 characters instead of every single character, giving
    increased performance.

    Jens

    --
    Jens de Smit
    Student Computer Science | Vrije Universiteit Amsterdam
    jfdsmit@few.vu.nl | http://www.few.vu.nl/~jfdsmit

  17. Re: strange behavior with C


    dr@kbrx.com writes:

    > Markus: By "unbuffered I/O is expensive" do you mean that running down
    > the input or output channel for each single byte takes time? I'm assuming
    > this is your meaning, but always best to verify.
    >
    > Hul



    Yes.

    And please don't top post. I do not want to have to edit posts
    extensively to restore a sane order.

    Regards -- Markus




+ Reply to Thread