return (i = 1, NULL)

Discussion in 'C Programming' started by William Ahern, Aug 24, 2003.

  1. is this legal:

    FILE *func(void) {
    extern int errno;

    return (errno = EINVAL, NULL);
    }

    my compiler (gcc 2.9.x on openbsd) is complaining that i'm returning a
    pointer from int w/o a cast. gcc 3.x on linux, however, never made a peep
    about it, so possibly 2.9.x is just grumpy.

    i suppose the relevent question is, can one group different types like
    that?

    tia,

    Bill
    William Ahern, Aug 24, 2003
    #1
    1. Advertising

  2. Ben Pfaff <> wrote:
    > William Ahern <william@wilbur.25thandClement.com> writes:


    >> is this legal:
    >>
    >> FILE *func(void) {
    >> extern int errno;
    >>
    >> return (errno = EINVAL, NULL);
    >> }


    > No. You can't declare `errno' yourself like that (it's not
    > necessarily a variable) and you forgot to #include <stdio.h>.


    > If you fix those two problems, then yes.


    yes. yeah.*

    > If you fix those two problems, then yes.


    that's what i thought. thanx.

    - Bill

    * - http://www.ebaumsworld.com/arnolds3.html
    William Ahern, Aug 24, 2003
    #2
    1. Advertising

  3. William Ahern

    Jun Woong Guest

    "William Ahern" <william@wilbur.25thandClement.com> wrote in message news:36kn11-itr.ln1@wilbur.25thandClement.com...
    > is this legal:
    >
    > FILE *func(void) {
    > extern int errno;
    >
    > return (errno = EINVAL, NULL);
    > }
    >
    > my compiler (gcc 2.9.x on openbsd) is complaining that i'm returning a
    > pointer from int w/o a cast. gcc 3.x on linux, however, never made a peep
    > about it, so possibly 2.9.x is just grumpy.
    >


    To avoid the discussion on the name space pollution, let me rewrite
    your code:

    FILE *func(void)
    {
    extern int my_errno;

    return (my_errno = SOME_VALUE, NULL);
    }

    And the expression given to the return statement is not a constant
    expression, becuase it contains the comma operator. Therefore, in the
    *full* expression for the return, NULL doesn't qualify as a null
    pointer constant. If your implementation #defines NULL simply as 0 (or
    similar ones whose types are not assignment-compatible with FILE *),
    your program is illegal, which is what gcc complains about.


    --
    Jun, Woong ()
    Jun Woong, Aug 25, 2003
    #3
  4. William Ahern <william@wilbur.25thandClement.com> wrote in message news:<36kn11-itr.ln1@wilbur.25thandClement.com>...
    > is this legal:
    >
    > FILE *func(void) {
    > extern int errno;
    >
    > return (errno = EINVAL, NULL);
    > }
    >
    > my compiler (gcc 2.9.x on openbsd) is complaining that i'm returning a
    > pointer from int w/o a cast. gcc 3.x on linux, however, never made a peep
    > about it, so possibly 2.9.x is just grumpy.


    Compiler bug. The return statement does not require ( ), incidentally.

    Sam
    Samuel Barber, Aug 25, 2003
    #4
  5. On 25 Aug 2003 01:02:48 -0700, Samuel Barber <> wrote:
    > William Ahern <william@wilbur.25thandClement.com> wrote in message
    > news:<36kn11-itr.ln1@wilbur.25thandClement.com>...
    >> is this legal:
    >>
    >> FILE *func(void) {
    >> extern int errno;
    >>
    >> return (errno = EINVAL, NULL);
    >> }
    >>
    >> my compiler (gcc 2.9.x on openbsd) is complaining that i'm returning a
    >> pointer from int w/o a cast. gcc 3.x on linux, however, never made a peep
    >> about it, so possibly 2.9.x is just grumpy.

    >
    > Compiler bug. The return statement does not require ( ), incidentally.


    It's not a compiler bug. On FreeBSD, and thus I assume OpenBSD, NULL is
    an unadorned zero:
    #define NULL 0

    On Linux, it's
    #define NULL ((void*)0)

    Both are legal definitions of NULL. However, in some circumstances the
    differences can bite you. This is one of those.

    Since the function is defined as returning a pointer, you should return
    a pointer (surprise). The issue here is what, exactly, a null pointer
    is.

    A plain old zero is allowed to be a null pointer, given the proper
    context. One of the constraints is that it must be a constant
    expression, and the comma operator is not allowed in a constant
    expression.

    So, assuming NULL is just zero, we have something like:
    return (errno = EINVAL, 0);

    The value that's being returned has type integer, and is zero. But
    it's not a constant expression, and thus converting it to a pointer type
    isn't going to create a null pointer (or rather, it might or might not
    depending on your implementation, but it's safer to assume it won't.)

    However, if NULL is ((void*)0), then it's:
    return (errno = EINVAL, ((void*)0));

    The value being returned here has type void*, and is a null pointer. It
    is not a constant expression, but that's OK, because a constant
    expression is only required to convert an integer zero to a null
    pointer, not to convert a null pointer to another pointer type.

    This is a very confusing part of C, but it does show why you should
    always pretend NULL is just a plain old zero. In fact, some people
    refuse to use NULL at all because of issues like this; instead, they
    just use a zero as a null pointer. I like NULL, personally, because I
    know when to cast it and using NULL just makes the code a bit more self
    documenting, IMO.

    To be complete, the proper fix for the above code is:
    return (errno = EINVAL, (void*)NULL);
    or
    return (errno = EINVAL, (void*)0);
    or
    ... something that doesn't use the comma operator!

    Chris
    Chris Spiegel, Aug 25, 2003
    #5
  6. Chris Spiegel <> wrote in message news:<>...
    > A plain old zero is allowed to be a null pointer, given the proper
    > context. One of the constraints is that it must be a constant
    > expression, and the comma operator is not allowed in a constant
    > expression.
    >
    > So, assuming NULL is just zero, we have something like:
    > return (errno = EINVAL, 0);
    >
    > The value that's being returned has type integer, and is zero. But
    > it's not a constant expression, and thus converting it to a pointer type
    > isn't going to create a null pointer (or rather, it might or might not
    > depending on your implementation, but it's safer to assume it won't.)
    >
    > However, if NULL is ((void*)0), then it's:
    > return (errno = EINVAL, ((void*)0));
    >
    > The value being returned here has type void*, and is a null pointer. It
    > is not a constant expression, but that's OK, because a constant
    > expression is only required to convert an integer zero to a null
    > pointer, not to convert a null pointer to another pointer type.


    Thank you for the correction.

    > To be complete, the proper fix for the above code is:
    > return (errno = EINVAL, (void*)NULL);
    > or
    > return (errno = EINVAL, (void*)0);
    > or
    > .. something that doesn't use the comma operator!


    The last is by far the best fix, most importantly because (void*)0 is
    not portable to C++.

    Sam
    Samuel Barber, Aug 25, 2003
    #6
  7. Samuel Barber <> wrote:
    > Chris Spiegel <> wrote in message news:<>...

    <snip>
    >> To be complete, the proper fix for the above code is:
    >> return (errno = EINVAL, (void*)NULL);
    >> or
    >> return (errno = EINVAL, (void*)0);
    >> or
    >> .. something that doesn't use the comma operator!

    >
    > The last is by far the best fix, most importantly because (void*)0 is
    > not portable to C++.
    >
    > Sam


    I liked the comma form because of its expressiveness. I've used it
    exclusively w/ setting errno in a bunch of code (tho, this was the only
    instance where I was returning a pointer rather than an int). In these cases
    you really are returning two values, and it makes the code much more
    readable w/o the additional braces since I love to do a lot of sanity
    checking (since I never know where I might copy+paste the code).

    But, I'll be mindful of the pitfalls. Thanks Chris for the great
    explanation.

    - Bill
    William Ahern, Aug 26, 2003
    #7
  8. William Ahern

    Ben Pfaff Guest

    (Samuel Barber) writes:

    > The last is by far the best fix, most importantly because (void*)0 is
    > not portable to C++.


    When writing C code, there is no reason to worry about what C++
    compilers will think of it. (Header files are a possible
    exception.)
    --
    "The expression isn't unclear *at all* and only an expert could actually
    have doubts about it"
    --Dan Pop
    Ben Pfaff, Aug 26, 2003
    #8
  9. >> return (my_errno = SOME_VALUE, NULL);


    Why not:

    my_errno = SOME_VALUE; return NULL;

    --
    #include <standard.disclaimer>
    _
    Kevin D Quitt USA 91387-4454 96.37% of all statistics are made up
    Per the FCA, this address may not be added to any commercial mail list
    Kevin D. Quitt, Aug 26, 2003
    #9
  10. Kevin D. Quitt <> wrote:
    >>> return (my_errno = SOME_VALUE, NULL);

    >
    >
    > Why not:
    >
    > my_errno = SOME_VALUE; return NULL;


    Because I usually use brevity and clarity like so:

    if (check_parameter)
    return (errno = EINVAL, NULL);

    Tho, this was the first time I had to return a null pointer rather
    than another error identifer like -1.

    The alterntives are:

    if (some_condition) {
    errno = EINVAL;
    return NULL;
    }

    [three or four more time]

    or

    if (some_condition1 || some_condition2 || some_condition3 || ...) {
    errno = (some_condition)? ENAMETOOLONG : EINVAL
    return NULL;
    }

    Neither of those are very satisfactory for code that isn't even central
    to the purpose of the function.
    William Ahern, Aug 27, 2003
    #10
  11. On Tue, 26 Aug 2003, William Ahern wrote:
    >
    > Kevin D. Quitt <> wrote:
    > >>> return (my_errno = SOME_VALUE, NULL);

    > >
    > > Why not:
    > >
    > > my_errno = SOME_VALUE; return NULL;

    >
    > Because I usually use brevity and clarity like so:
    >
    > if (check_parameter)
    > return (errno = EINVAL, NULL);
    >
    > Tho, this was the first time I had to return a null pointer rather
    > than another error identifer like -1.
    >
    > The alternatives are:
    >
    > if (some_condition) {
    > errno = EINVAL;
    > return NULL;
    > }


    > or
    >
    > if (some_condition1 || some_condition2 || some_condition3 || ...) {
    > errno = (some_condition)? ENAMETOOLONG : EINVAL
    > return NULL;
    > }


    I think the simplest solution has been determined to be:

    if (some_condition)
    return (errno = EINVAL, (void *) NULL);

    Still, I agree that this is almost certainly obfuscation. Have
    you considered my /idiom du jour/,

    if (some_condition1)
    goto exit_failure1;
    if (some_condition2)
    goto exit_failure2;
    ...

    exit_failure1:
    errno = EINVAL;
    return NULL;

    exit_failure2:
    errno = ENAMETOOLONG;
    return NULL;


    Very compact, and has the added bonus that all the "exit" code is in
    one place. That means it's harder to miss a free(), and easier to
    figure out all the possible return codes (which should be documented
    anyway, of course, but still..).

    HTH,
    -Arthur
    Arthur J. O'Dwyer, Aug 27, 2003
    #11
  12. Ben Pfaff <> wrote in message news:<>...
    > (Samuel Barber) writes:
    >
    > > The last is by far the best fix, most importantly because (void*)0 is
    > > not portable to C++.

    >
    > When writing C code, there is no reason to worry about what C++
    > compilers will think of it. (Header files are a possible
    > exception.)


    C code is not neccessarily bad if it's not C++-compatible, but
    C++-compatibility is certainly a valid point when considering the
    merits of a C code fragment in the abstract. There are many reasons to
    prefer C++ compatibility, all things being equal.

    Sam
    Samuel Barber, Aug 27, 2003
    #12
  13. William Ahern

    Greg Comeau Guest

    In article <>,
    Samuel Barber <> wrote:
    >Ben Pfaff <> wrote in message news:<>...
    >> (Samuel Barber) writes:
    >>
    >> > The last is by far the best fix, most importantly because (void*)0 is
    >> > not portable to C++.

    >>
    >> When writing C code, there is no reason to worry about what C++
    >> compilers will think of it. (Header files are a possible
    >> exception.)

    >
    >C code is not neccessarily bad if it's not C++-compatible, but
    >C++-compatibility is certainly a valid point when considering the
    >merits of a C code fragment in the abstract. There are many reasons to
    >prefer C++ compatibility, all things being equal.


    I think Sam has a reasonable point. Of course, it need not
    always be the case, but clearly many C programmers
    do -- and should -- worry about what C++ compilers will think.
    --
    Greg Comeau/4.3.3:Full C++03 core language + more Windows backends
    Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
    World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
    Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
    Greg Comeau, Aug 27, 2003
    #13
  14. William Ahern

    Greg Comeau Guest

    In article <newscache$uuv9kh$x97$>,
    Kevin Easton <> wrote:
    >Greg Comeau <> wrote:
    >> In article <>,
    >> Samuel Barber <> wrote:
    >>>Ben Pfaff <> wrote in message news:<>...
    >>>> (Samuel Barber) writes:
    >>>>
    >>>> > The last is by far the best fix, most importantly because (void*)0 is
    >>>> > not portable to C++.
    >>>>
    >>>> When writing C code, there is no reason to worry about what C++
    >>>> compilers will think of it. (Header files are a possible
    >>>> exception.)
    >>>
    >>>C code is not neccessarily bad if it's not C++-compatible, but
    >>>C++-compatibility is certainly a valid point when considering the
    >>>merits of a C code fragment in the abstract. There are many reasons to
    >>>prefer C++ compatibility, all things being equal.

    >>
    >> I think Sam has a reasonable point. Of course, it need not
    >> always be the case, but clearly many C programmers
    >> do -- and should -- worry about what C++ compilers will think.

    >
    >Since C translation units can be linked into C++ programs, why can't
    >they just compile their .c files with a C compiler, even when they're
    >part of a C++ project?


    They can. But to require everybody do so is not always
    sufficient, just like not requiring them to do so isn't.
    When/If an obvious gain can be made, it should be considered,
    in context.
    --
    Greg Comeau/4.3.3:Full C++03 core language + more Windows backends
    Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
    World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
    Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
    Greg Comeau, Aug 27, 2003
    #14
  15. Arthur J. O'Dwyer <> wrote:
    > I think the simplest solution has been determined to be:
    >
    > if (some_condition)
    > return (errno = EINVAL, (void *) NULL);
    >
    > Still, I agree that this is almost certainly obfuscation. Have
    > you considered my /idiom du jour/,
    >
    > if (some_condition1)
    > goto exit_failure1;
    > if (some_condition2)
    > goto exit_failure2;
    > ...
    >
    > exit_failure1:
    > errno = EINVAL;
    > return NULL;
    >
    > exit_failure2:
    > errno = ENAMETOOLONG;
    > return NULL;
    >
    > Very compact, and has the added bonus that all the "exit" code is in
    > one place. That means it's harder to miss a free(), and easier to
    > figure out all the possible return codes (which should be documented
    > anyway, of course, but still..).


    yes ;) i use that extensively, tho i usually limit it to a simple "goto
    fail", otherwise things seem a little too cluttered to me (trying to juggle
    multiple labels). instead i'll initialize the relevent values so that the
    fail section knows what to clean up and what not to. and so i might do
    something like:

    if (cond) {
    errno = EINVAL;
    goto fail;
    }

    anyhoo, this has been an interesting thread, at least for myself.

    thanx all.

    [END OF THREAD]
    William Ahern, Aug 28, 2003
    #15
    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. Kivak Wolf
    Replies:
    2
    Views:
    10,059
    Kivak Wolf
    Jun 28, 2005
  2. Replies:
    5
    Views:
    26,505
    Mike Schilling
    Mar 29, 2006
  3. Carl
    Replies:
    21
    Views:
    975
    Patricia Shanahan
    Aug 24, 2006
  4. Greenhorn
    Replies:
    15
    Views:
    800
    Keith Thompson
    Mar 6, 2005
  5. Francois Grieu
    Replies:
    14
    Views:
    788
    Micah Cowan
    Mar 7, 2008
Loading...

Share This Page