Search code examples
ccygwin

Confusing sequence of Code flow on Cygwin


There is this exceptionally simple program in C (built with gcc on Cygwin)::

// This program is a tutorial to Stack-based overflow, that's why "gets"
    #include <stdio.h>

    void test()
    {
        char buff[4];
        printf("Some input: ");
        gets(buff);
        puts(buff);
    }

    int main(int argc, char** argv)
    {
        test();
        return 0;
    }

Now when I run this on Windows console,printf executes first and waits for the input:: enter image description here

But when I run the same exe under Cygwin terminal, it waits for the input and then printf executes::

enter image description here

Why is this difference?

EDIT:: With \n appended to the string in printf statement, the behaviour remains the same::

enter image description here


Solution

  • So, after some reading and research, I concluded at a final theory for this behaviour.

    Short Answer:: stdout is buffered, so doing a

    void test()
    {
        char buff[4];
        setvbuf(stdout, NULL, _IONBF, 0); // <--- setting stdout to _IONBF
        printf("Some input: ");
        gets(buff);
        puts(buff);
    }
    

    before printing anything to console or,

    void test()
        {
            char buff[4];
            printf("Some input: ");
            fflush(stdout); // <--- force the stdout to flush
            gets(buff);
            puts(buff);
        }
    

    after the printf statement will solve the issue.

    Long Answer::

    When I run the same exe with Bash.exe, the stdout is not buffered:: enter image description here

    And the same exe with mintty.exe, the stdout is buffered:: enter image description here

    Now the question is,

    • why stdout is unbuffered in one and buffered on another?

    As you can see the tty output on both, bash shows as console session /dev/cons0, whereas the mintty shows as pseudo-terminal session /dev/pty0.

    So,

    • how does it answer the question of unbuffered and buffered stdout?

    My browsing re-re-and-re searches landed me here, stating, If I type tty in the respective Cygwin windows, I see that mintty and xterm are both pseudo-terminals whereas bash is a console session - I believe procServ uses forkpty(). So I think it boils down to Windows treating a Cygwin pty as non-interactive and thus buffering both stdout and stderr.

    I am not sure, how precise this is but yes, this seems to be a practical and best explanation of this behaviour.

    According to Section 7.9.13/7 of c99 states that:

    At program start-up, three text streams are predefined and need not be opened explicitly - standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output).

    As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.

    *The bold emphasis is mine.