Why does write() to stdin work?

Discussion in 'C Programming' started by ishwar.rattan@gmail.com, Apr 23, 2013.

  1. Guest

    Tried the following code under gcc and it writes to stdin??

    #include <stdio.h>
    #include <stdlib.h>

    int main()
    {
    int k;
    for(k= 0; k < 4; k++)
    write(k, "Hello world!\n", 13);
    }

    Any poiners?
    -ishwar
    , Apr 23, 2013
    #1
    1. Advertising

  2. osmium Guest

    <> wrote:

    > Tried the following code under gcc and it writes to stdin??
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main()
    > {
    > int k;
    > for(k= 0; k < 4; k++)
    > write(k, "Hello world!\n", 13);
    > }
    >
    > Any poiners?


    There is an "fwrite()" in C but no "write()". so you must have stumbled
    across a gcc extension. There is probably a command line way to force gcc
    to do ANSI C if you don't like this result.
    osmium, Apr 23, 2013
    #2
    1. Advertising

  3. James Kuyper Guest

    On 04/23/2013 09:59 AM, wrote:
    > Tried the following code under gcc and it writes to stdin??
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main()
    > {
    > int k;
    > for(k= 0; k < 4; k++)
    > write(k, "Hello world!\n", 13);
    > }
    >
    > Any poiners?


    write() is not a C standard library function, so the reason why it did
    or did not work depends upon the library that provides write(), so your
    question should be directed to a forum appropriate to that library. If,
    for instance, it's the Unix standard library function, then you should
    try comp.unix.programmer.

    How do you know that it worked? As far as I can tell, your program makes
    no attempt to determine whether or not the call to write() was
    successful. For example, if this is the Unix function, your code doesn't
    check the return value from write(), which should be 13 for a successful
    call, nor does it check the value of errno, which should be 0 after a
    successful call, unless it was already set to a non-zero value before
    the call.
    James Kuyper, Apr 23, 2013
    #3
  4. Guest

    On Tuesday, April 23, 2013 11:58:43 AM UTC-4, James Kuyper wrote:
    >
    > > Tried the following code under gcc and it writes to stdin??

    >
    > >

    >
    > > #include <stdio.h>

    >
    > > #include <stdlib.h>

    >
    > >

    >
    > > int main()

    >
    > > {

    >
    > > int k;

    >
    > > for(k= 0; k < 4; k++)

    >
    > > write(k, "Hello world!\n", 13);

    >
    > > }

    >
    > >

    >
    > > Any poiners?

    >
    >
    >
    > write() is not a C standard library function, so the reason why it did
    >
    > or did not work depends upon the library that provides write(), so your
    >
    > question should be directed to a forum appropriate to that library. If,
    >
    > for instance, it's the Unix standard library function, then you should
    >
    > try comp.unix.programmer.
    >
    >
    >
    > How do you know that it worked? As far as I can tell, your program makes
    >
    > no attempt to determine whether or not the call to write() was
    >
    > successful. For example, if this is the Unix function, your code doesn't
    >
    > check the return value from write(), which should be 13 for a successful
    >
    > call, nor does it check the value of errno, which should be 0 after a
    >
    > successful call, unless it was already set to a non-zero value before
    >
    > the call.


    write() a is system call Unix systems, does not return failure and I will try comp.unix.programmer group.

    Thanks for the effort.

    -ishwar
    , Apr 23, 2013
    #4
  5. "osmium" <> writes:
    > <> wrote:
    >> Tried the following code under gcc and it writes to stdin??
    >>
    >> #include <stdio.h>
    >> #include <stdlib.h>
    >>
    >> int main()
    >> {
    >> int k;
    >> for(k= 0; k < 4; k++)
    >> write(k, "Hello world!\n", 13);
    >> }
    >>
    >> Any poiners?

    >
    > There is an "fwrite()" in C but no "write()". so you must have stumbled
    > across a gcc extension. There is probably a command line way to force gcc
    > to do ANSI C if you don't like this result.


    write() isn't a gcc extension; it's defined by POSIX.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 23, 2013
    #5
  6. Nobody Guest

    On Tue, 23 Apr 2013 09:39:48 -0700, ishwar.rattan wrote:

    > write() a is system call Unix systems, does not return failure


    On success, it returns the number of bytes written. On failure, it returns
    -1 and sets errno to indicate the nature of the failure. In your example,
    it will return -1 and set errno to EBADF.
    Nobody, Apr 24, 2013
    #6
  7. It doesn't work.

    You just got very lucky the one time you tried it, probably because you
    left stdin connected to your terminal which is also an output device
    *and* you happened to be linked to a runtime library that let you get
    away with it. Under different conditions, your code would probably fail.

    You have encountered undefined behavior. From my quotes file:

    What undefined means is:

    undefined.
    Do not rely on the results.
    You have gone outside the domain of the function
    You have broken the programming model of the C language.
    Here there be dragons!
    The implementors can do anything they want.
    Be careful.
    Use a different algorithm.
    This is non-portable.
    Don't do it.


    Here's one of the rules about being a good programmer: Don't
    just try things until they work. Read the documentation and
    write code that adheres to the specifications. Just because
    it worked today doesn't mean it will work tomorrow.

    --
    -Ed Falk,
    http://thespamdiaries.blogspot.com/
    Edward A. Falk, Apr 24, 2013
    #7
  8. Nobody <> wrote:
    > On Tue, 23 Apr 2013 09:39:48 -0700, ishwar.rattan wrote:


    >> write() a is system call Unix systems, does not return failure


    > On success, it returns the number of bytes written. On failure,
    > it returns -1 and sets errno to indicate the nature of the failure.
    > In your example, it will return -1 and set errno to EBADF.


    There is no rule against writing to file descriptor zero.

    The convention for inetd programs is that they read and write
    of fd 0.

    If fd 0 is a terminal, writing should be fine.

    -- glen
    glen herrmannsfeldt, Apr 24, 2013
    #8
  9. Ian Collins Guest

    wrote:
    > Tried the following code under gcc and it writes to stdin??
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main()
    > {
    > int k;
    > for(k= 0; k < 4; k++)
    > write(k, "Hello world!\n", 13);
    > }


    Just one thing to add: check the return value of write (always good
    practice) and you will see where your code fails.

    --
    Ian Collins
    Ian Collins, Apr 24, 2013
    #9
  10. (Edward A. Falk) writes:
    > It doesn't work.
    >
    > You just got very lucky the one time you tried it, probably because you
    > left stdin connected to your terminal which is also an output device
    > *and* you happened to be linked to a runtime library that let you get
    > away with it. Under different conditions, your code would probably fail.
    >
    > You have encountered undefined behavior. From my quotes file:
    >
    > What undefined means is:
    >
    > undefined.
    > Do not rely on the results.
    > You have gone outside the domain of the function
    > You have broken the programming model of the C language.
    > Here there be dragons!
    > The implementors can do anything they want.
    > Be careful.
    > Use a different algorithm.
    > This is non-portable.
    > Don't do it.
    >
    >
    > Here's one of the rules about being a good programmer: Don't
    > just try things until they work. Read the documentation and
    > write code that adheres to the specifications. Just because
    > it worked today doesn't mean it will work tomorrow.


    How is the behavior undefined?

    If you mean that the C standard doesn't define the behavior of
    write(), that's true but hardly useful; the POSIX standard does.

    Somewhat off-topic:

    As far as I can tell from a quick reading of the POSIX specification,
    a call to write() can either succeed or fail. I'd naively expect
    it to fail on an attempt to write to a file descriptor not opened
    for writing, but I don't see anything that says it's *required*
    to fail. And even if it were, failure is not undefined behavior;
    write() would simply return -1 and set errno.

    (I certainly think that writing to stdin is a silly thing to do.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 24, 2013
    #10
  11. On Tue, 23 Apr 2013 20:58:45 -0700, Keith Thompson <>
    wrote:

    > (Edward A. Falk) writes:
    >> It doesn't work.
    >>
    >> You just got very lucky the one time you tried it, probably because you
    >> left stdin connected to your terminal which is also an output device
    >> *and* you happened to be linked to a runtime library that let you get
    >> away with it. Under different conditions, your code would probably fail.
    >>
    >> You have encountered undefined behavior. From my quotes file:
    >>
    >> What undefined means is:
    >>
    >> undefined.
    >> Do not rely on the results.
    >> You have gone outside the domain of the function
    >> You have broken the programming model of the C language.
    >> Here there be dragons!
    >> The implementors can do anything they want.
    >> Be careful.
    >> Use a different algorithm.
    >> This is non-portable.
    >> Don't do it.
    >>
    >>
    >> Here's one of the rules about being a good programmer: Don't
    >> just try things until they work. Read the documentation and
    >> write code that adheres to the specifications. Just because
    >> it worked today doesn't mean it will work tomorrow.

    >
    >How is the behavior undefined?


    If he is indeed using the posix function, then the third argument
    needs to be a size_t, not an int. But there is no prototype in scope
    for write so the compiler does not know to convert the 13 to a size_t.
    size_t need not have the same size as int and unsigned int..

    And the second argument passes muster only because void* and char* are
    guaranteed to have the same representation and alignment. I don't
    think the absence of the const qualifier on this argument changes
    anything one way or the other.

    --
    Remove del for email
    Barry Schwarz, Apr 24, 2013
    #11
  12. James Kuyper Guest

    On 04/23/2013 10:55 PM, Ian Collins wrote:
    > wrote:
    >> Tried the following code under gcc and it writes to stdin??
    >>
    >> #include <stdio.h>
    >> #include <stdlib.h>
    >>
    >> int main()
    >> {
    >> int k;
    >> for(k= 0; k < 4; k++)
    >> write(k, "Hello world!\n", 13);
    >> }

    >
    > Just one thing to add: check the return value of write (always good
    > practice) and you will see where your code fails.
    >


    #define _POSIX_C_SOURCE 1
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(void)
    {
    int k;
    printf("stdin:%d stdout:%d stderr:%d\n",
    fileno(stdin), fileno(stdout), fileno(stderr));
    for(k= 0; k < 4; k++)
    {
    errno = 0;
    int bytes = write(k, "Hello world!\n", 13);
    printf("k:%d bytes:%d errno:%d\n", k, bytes, errno);
    }
    return 0;
    }


    Output:
    stdin:0 stdout:1 stderr:2
    Hello world!
    k:0 bytes:13 errno:0
    Hello world!
    k:1 bytes:13 errno:0
    Hello world!
    k:2 bytes:13 errno:0
    k:3 bytes:-1 errno:9
    --
    James Kuyper
    James Kuyper, Apr 24, 2013
    #12
  13. In article <>,
    Keith Thompson <> wrote:
    >
    >As far as I can tell from a quick reading of the POSIX specification,
    >a call to write() can either succeed or fail. I'd naively expect
    >it to fail on an attempt to write to a file descriptor not opened
    >for writing, but I don't see anything that says it's *required*
    >to fail.


    That's the undefined part. OP went outside the spec and got
    lucky. That won't always happen.

    --
    -Ed Falk,
    http://thespamdiaries.blogspot.com/
    Edward A. Falk, Apr 24, 2013
    #13
  14. (Edward A. Falk) writes:
    > In article <>,
    > Keith Thompson <> wrote:
    >>
    >>As far as I can tell from a quick reading of the POSIX specification,
    >>a call to write() can either succeed or fail. I'd naively expect
    >>it to fail on an attempt to write to a file descriptor not opened
    >>for writing, but I don't see anything that says it's *required*
    >>to fail.

    >
    > That's the undefined part. OP went outside the spec and got
    > lucky. That won't always happen.


    My interpretation of the POSIX spec is that write() either succeeds
    or fails. If you give it a bad pointer as the second argument,
    or a size for the third argument that exceeds the available data
    pointed to by the second argument, the behavior is undefined.
    But if you pass 0 (standard input) as the first argument, that's
    a valid file descriptor argument -- just one you might not have
    *permission* to write to.

    Quoting the POSIX spec
    (http://pubs.opengroup.org/onlinepubs/9699919799/toc.htm):

    These functions shall fail if:
    ...
    [EBADF]
    The fildes argument is not a valid file descriptor open for
    writing.

    That looks pretty well-defined to me.

    The implementation *might* be non-conforming because it permits
    writes to standard input, but I don't see any permission for the
    implementation to throw up its hands and unleash the nasal demons.
    I'd have to look further to determine whether 0 may be considered
    to be "open for writing"; searching the spec for "0" is unlikely
    to be useful.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 24, 2013
    #14
  15. Barry Schwarz <> writes:
    > On Tue, 23 Apr 2013 20:58:45 -0700, Keith Thompson <>
    > wrote:

    [...]
    >>How is the behavior undefined?

    >
    > If he is indeed using the posix function, then the third argument
    > needs to be a size_t, not an int. But there is no prototype in scope
    > for write so the compiler does not know to convert the 13 to a size_t.
    > size_t need not have the same size as int and unsigned int..
    >
    > And the second argument passes muster only because void* and char* are
    > guaranteed to have the same representation and alignment. I don't
    > think the absence of the const qualifier on this argument changes
    > anything one way or the other.


    There is no *declaration* in scope, prototype or not. The call is a
    constraint violation; there is no implication in the standard that it
    will even *attempt* to convert the int argument to size_t.

    So yes, given the missing #include directive the program's behavior is
    undefined *if* the compiler doesn't simply reject it.

    (But that's not what Ed Falk was referring to.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 24, 2013
    #15
  16. James Kuyper Guest

    On 04/24/2013 11:38 AM, Keith Thompson wrote:
    ....
    > My interpretation of the POSIX spec is that write() either succeeds
    > or fails. If you give it a bad pointer as the second argument,
    > or a size for the third argument that exceeds the available data
    > pointed to by the second argument, the behavior is undefined.
    > But if you pass 0 (standard input) as the first argument, that's
    > a valid file descriptor argument -- just one you might not have
    > *permission* to write to.
    >
    > Quoting the POSIX spec
    > (http://pubs.opengroup.org/onlinepubs/9699919799/toc.htm):
    >
    > These functions shall fail if:
    > ...
    > [EBADF]
    > The fildes argument is not a valid file descriptor open for
    > writing.
    >
    > That looks pretty well-defined to me.
    >
    > The implementation *might* be non-conforming because it permits
    > writes to standard input, but I don't see any permission for the
    > implementation to throw up its hands and unleash the nasal demons.
    > I'd have to look further to determine whether 0 may be considered
    > to be "open for writing"; searching the spec for "0" is unlikely
    > to be useful.


    I searched for stdin, and found:

    "At program start-up, three streams shall be 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)."
    Note that it does not say "opened for reading only" or "opened for
    writing only". Oddly enough, it does specify:

    "The stderr stream is expected to be open for reading and writing." I've
    never even thought about the possibility of reading from stderr - I
    wonder what the use case was that prompted that change (it was
    introduced in Issue 6)? If stderr is seekable, I suppose one part of a
    process could read an error message produced by a different part of the
    process?
    James Kuyper, Apr 24, 2013
    #16
  17. James Kuyper <> wrote:

    (snip)

    > I searched for stdin, and found:


    > "At program start-up, three streams shall be 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)."
    > Note that it does not say "opened for reading only" or "opened for
    > writing only". Oddly enough, it does specify:


    > "The stderr stream is expected to be open for reading and writing." I've
    > never even thought about the possibility of reading from stderr - I
    > wonder what the use case was that prompted that change (it was
    > introduced in Issue 6)? If stderr is seekable, I suppose one part of a
    > process could read an error message produced by a different part of the
    > process?


    (snip)

    I haven't thought about this one for a while.

    Consider programs that might have both stdin and stdout redirected,
    then write a question (do you really want to ...?) to stderr, and then
    wait for a reply. Where do you read the reply from?

    -- glen
    glen herrmannsfeldt, Apr 24, 2013
    #17
  18. In article <>,
    Barry Schwarz <> wrote:
    >
    >If he is indeed using the posix function, then the third argument
    >needs to be a size_t, not an int. But there is no prototype in scope
    >for write so the compiler does not know to convert the 13 to a size_t.
    >size_t need not have the same size as int and unsigned int..


    Ahh, I totally missed that part.

    This brings me back to what I said about following the spec
    and not just trying things until it works.

    The write(2) man page says to #include <unistd.h> in order to
    call this function. If you don't do this, then you're doing
    it wrong.

    I've been programming C for a living for a very long time, and
    I still read the man pages before I call a function, just to
    be sure.

    --
    -Ed Falk,
    http://thespamdiaries.blogspot.com/
    Edward A. Falk, Apr 24, 2013
    #18
  19. Ken Brody Guest

    On 4/23/2013 9:59 AM, wrote:
    > Tried the following code under gcc and it writes to stdin??
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main()
    > {
    > int k;
    > for(k= 0; k < 4; k++)
    > write(k, "Hello world!\n", 13);
    > }
    >
    > Any poiners?


    My guess is that, in your environment, stdin and stdout, while being
    different handles, are actually duplicate read/write handles to the current
    tty. At least by default.

    Consider redirecting stdin, so that it is not a duplicate of stdout, and see
    if you get the same results:

    echo | my_program

    However, this whole topic is OT for clc, as write() is not standard C but
    POSIX. And even then, you may be dealing with UB, as I doubt that there is
    any guarantee that stdin is writable.
    Ken Brody, Apr 25, 2013
    #19
  20. Ken Brody Guest

    On 4/24/2013 2:15 PM, glen herrmannsfeldt wrote:
    > James Kuyper <> wrote:

    [...]
    >> "The stderr stream is expected to be open for reading and writing." I've
    >> never even thought about the possibility of reading from stderr - I
    >> wonder what the use case was that prompted that change (it was
    >> introduced in Issue 6)? If stderr is seekable, I suppose one part of a
    >> process could read an error message produced by a different part of the
    >> process?

    >
    > (snip)
    >
    > I haven't thought about this one for a while.
    >
    > Consider programs that might have both stdin and stdout redirected,
    > then write a question (do you really want to ...?) to stderr, and then
    > wait for a reply. Where do you read the reply from?


    From "/dev/tty", of course. :)

    (BTW, I wouldn't use stderr for asking the question, either.)
    Ken Brody, Apr 25, 2013
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Johnathan Doe

    peek at stdin, flush stdin

    Johnathan Doe, May 15, 2004, in forum: C Programming
    Replies:
    5
    Views:
    24,923
    Chatoyer
    May 17, 2013
  2. Charlie Zender

    Reading stdin once confuses second stdin read

    Charlie Zender, Jun 19, 2004, in forum: C Programming
    Replies:
    6
    Views:
    783
    Dan Pop
    Jun 21, 2004
  3. Horace Nunley

    why why why does function not work

    Horace Nunley, Sep 27, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    455
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Sep 27, 2006
  4. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,804
    Smokey Grindel
    Dec 2, 2006
  5. Ben
    Replies:
    2
    Views:
    1,336
    jacob navia
    Aug 29, 2009
Loading...

Share This Page