Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Read in bash : stdin and stdout

I have a simple C program with the read function and I don't understand the output.

//code1.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{

    int r;
    char c; // In C, char values are stored in 1 byte

    r = read ( 0, &c, 1);

    // DOC:
    //ssize_t read (int filedes, void *buffer, size_t size)
    //The read function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer.
    //The return value is the number of bytes actually read.

    // Here:
    // filedes is 0, which is stdin from <stdio.h>
    // *buffer is &c : address in memory of char c
    // size is 1 meaning it will read only 1 byte

    printf ("r = %d\n", r);

    return 0;
}

And here is a screenshot of the result:

Screenshot of program executio

I ran this program 2 times as showed above and typed "a" for the first try and "aecho hi" for the second try.

How I try to explain the results:

  1. When read is called it sees that stdin is closed and opens it (from my point of view, why? It should just read it. I don't know why it opens it).
  2. I type "aecho hi" in the bash and press enter.
  3. read has priority to process stdin and reads the first byte of "aecho hi" : "a".
  4. I get the confirmation that read has processed 1 byte with the printf.
  5. a.out has finished and is terminated.
  6. Somehow the remaining data in stdin is processed in bash (the father of my program) and goes to stdout which executes it and for some reason the first byte has been deleted by read.

This is all hypothetical and very blurry. Any help understanding what is happening would be very welcome.

like image 533
shrimpdrake Avatar asked Oct 30 '25 18:10

shrimpdrake


2 Answers

When you type at your terminal emulator, it writes your keystrokes to a "file", in this case an in-memory buffer that, thanks to the file system, looks just like any other file that might be on disk.

Every process inherits 3 open file handles from its parent. We are interested in one of them here, standard input. The program executed by the terminal emulator (here, bash), is given as its standard input the in-memory buffer described in the first paragraph.

a.out, when run by bash, also receives this same file as its standard input. Keep this in mind: bash and a.out are reading from the same, already-opened file.

After you run a.out, its read blocks, because its standard input is empty. When you type aecho hi<enter>, the terminal writes these characters to the buffer (<enter> becoming a single linefeed character). a.out only requests one character, so it gets a and leaves the rest of the characters in the file. (Or more precisely, the file pointer is still pointing at the e after a is read.)

After a.out completes, bash tries to read from the same file. Normally, the file is empty (i.e., the file pointer is at the end of the file), so bash blocks waiting for another command. In this case, though, there is input available already: echo hi\n. bash reads this now the same as if you had typed it after a.out completed.

like image 126
chepner Avatar answered Nov 01 '25 09:11

chepner


Check this. As alk suggests stdin and stdout are already open with the program. Now you have to understand, once you type:

aecho hi

and hit return the stdin buffer is filled with all those letters (and space) - and will continue to be as long as you don't flush it. When the program exits, the stdin buffer is still full, and your terminal automatically handles a write into stdin by echoing it to stdout - this is what you're seeing at the end - your shell reading stdin.

Now as you point out, your code "presses return" for you so to speak - in the first execution adding an empty shell line, and in the second executing echo hi. But you must remember, you pressed return, so "\n" is in the buffer! To be explicit, you in fact typed:

aecho hi\n

Once your program exits the shell reads the remaining characters in the buffer, including the return, and that's what you see!

like image 42
kabanus Avatar answered Nov 01 '25 09:11

kabanus



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!