Was it always like that?

Discussion in 'C Programming' started by Melzzzzz, Feb 17, 2014.

  1. Melzzzzz

    Melzzzzz Guest

    I am really puzzled that I have to
    return from main.
    main.c:
    int main(void)
    {
    }

    bmaxa@maxa:~/examples$ gcc -Wall main.c
    main.c: In function ‘main’:
    main.c:3:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
    bmaxa@maxa:~/examples$ clang -Wall main.c
    bmaxa@maxa:~/examples$ icc -Wall main.c
    bmaxa@maxa:~/examples$

    Of three C compilers that I use, only gcc gives warning. What does
    it means? Is it something new or was always like that?
     
    Melzzzzz, Feb 17, 2014
    #1
    1. Advertisements

  2. You don't have to have an explicit return in C99 (and C11). Add, say,
    -std=c99 and (for my version of gcc) the warning goes away.
    It's just a choice that various compiler authors made. I'd prefer to
    told about a missing return when compiling ANSI C, but clang and icc
    chose not to do that. All compilers I tests correctly warn about
    missing return statements in other non-void functions, but main is a
    little different.
    Pass.
     
    Ben Bacarisse, Feb 17, 2014
    #2
    1. Advertisements

  3. Melzzzzz

    James Kuyper Guest

    You don't have to. Either main() a any subroutine thereof can enter an
    infinitely loop, or call any _Noreturn function, and that would not be
    problem (at least, not in itself - if done in the wrong context, it
    could cause other problems). The C standard library provides six
    _Noreturn functions: longjmp() (which doesn't really count for this
    purpose, since it just transfers control to some other part of the
    code), abort(), exit(), _Exit(), quick_exit(), and thrd_exit(), and
    people are allowed to define similar functions of their own.
    The above is not an example of failing to return from main(). There is
    an implicit return when execution of a program reaches the end of a
    function, which in this case happens immediately at the start of the
    program.
    The problem isn't a failure to return from main; your code does that.
    It's failing to provide a return value. main() is declared as returning
    an int value, and you've failed to provide one for it to return. Even
    that's not necessarily a problem: failing to provide a return value only
    has undefined behavior if the calling routine tries to use the return
    value that you failed to provide (6.9.1p12). I hope you can understand
    why that would be a problem?
    There's also a special exemption even from that rule, for main():
    reaching the end of main() without returning a value is implicitly
    equivalent to "return 0;" (5.1.2.2.3p1).

    That's why this is merely a warning, and not an error message. It is a
    bad idea to take advantage of the special exemption for main(), and
    dangerous to rely upon the exemption for return values that aren't used.
    A function that isn't supposed to be returning a value should be
    declared void. That return type isn't under your control for main(), so
    you should always return some value when exiting main(). However, in
    this particular case the behavior is well-defined.
    The only relevant rule that has changed is the special exemption for
    main(), which was added in C99. Before that, failing to return a value
    from main() had undefined behavior, because the caller to main() might
    (and almost certainly would) try to use the return value you had failed
    to provide.
     
    James Kuyper, Feb 17, 2014
    #3
  4. No, that's not why it's a warning.

    gcc by default is equivalent to "gcc -std=gnu89", which corresponds to
    1989 ANSI C with GNU extensions. In that dialect of C, reaching the
    closing "}" of main() returns an undefined status to the environment,
    and that's what gcc is warning about. (In fact when I compile and run
    "int main(void){}" with default options, it generally does return a
    non-zero status.)

    "gcc -std=c99" or later does not issue the warning, and it generates
    different code that returns a status of 0.
     
    Keith Thompson, Feb 17, 2014
    #4
  5. The defacto standard (prior to c99) was that if you didn't code an explicit
    "return" statement, then the return value (of just about any non-void
    function, not just main()) was the value most recently evaluated by the
    function. Yes, I know this wasn't a "standard" in the sense used by the
    religion of CLC; that's why I called it a "defacto" standard.

    This means that: int main(void) { puts("hello, world"); }
    would result in a return status of 13.

    Incidentally, int main(void) { puts("hello, world");20; }
    should result in a return status of 20, but modern compilers are too smart
    to be fooled by that... (Even with no optimization requested)

    --
    "I heard somebody say, 'Where's Nelson Mandela?' Well,
    Mandela's dead. Because Saddam killed all the Mandelas."

    George W. Bush, on the former South African president who
    is still very much alive, Sept. 20, 2007
     
    Kenny McCormack, Feb 17, 2014
    #5
  6. Well, before ANSI C, and so before void, functions were declared
    int if there was no other need for a type, and so would often not
    have a return statement.

    My K&R1 isn't handy, but I thought that it returned 0 in that case.

    Many calling conventions put int return values in a specific register.
    If the compiler doesn't load something, you get whatever happens to be
    in that register.

    -- glen
     
    glen herrmannsfeldt, Feb 17, 2014
    #6
  7. The pre-ANSI convention was to omit the return type (letting it
    default to int) for a function that doesn't return a value.

    Either executing a "return;" statement (with no expression) or falling
    off the end of a function would return an undefined value to the caller.

    If the caller doesn't attempt to use the value, there was no problem.
    Right.
     
    Keith Thompson, Feb 17, 2014
    #7
  8. Melzzzzz

    Joe Pfeiffer Guest

    Not on all platforms, and only by luck. In particular...

    I once made exactly this mistake (forgetting to return the result
    calculated) in a program originally meant for x86. As that value was
    indeed the last thing calculated, it happened to still be in the EAX
    register, which is used for function returns in that architecture.

    When the code was recompiled for SPARC, the value wound up in a register
    other than the one that was used for function returns. Ooops...
     
    Joe Pfeiffer, Feb 17, 2014
    #8
  9. (Thinking back to the old Hee Haw cornfield routine - with the tag line "If
    it weren't for bad luck, I'd have no luck at all")

    If it weren't for snarky, over-the-top, hyperbolic posts in CLC, we'd have
    no posts at all.

    (Yes, I'm looking at you, Joe)
     
    Kenny McCormack, Feb 18, 2014
    #9
  10. Melzzzzz

    Joe Pfeiffer Guest

    If giving a specific example of a compiler on a major vendor's platform
    which doesn't follow your "de facto standard" is snarky, over-the-top,
    and hyperbolic then I'm all three. I suppose quoting the 1975 C
    reference manual saying "Flowing off the end of a function is equivalent
    to a return with no returned value" (on page 14) would be equally
    over-the-top and hyperbolic.
     
    Joe Pfeiffer, Feb 18, 2014
    #10
  11. Melzzzzz

    Kaz Kylheku Guest

    So SPARC is weird and doesn't "conform" to Kenny's "de facto" standard.

    That could be related to the reason why we don't see SPARC-based chips in
    cellphones, tablests, or anywhere else, really.

    If they only had propagated the return value of a puts out of main
    with no return statement, things might be different today. :)
     
    Kaz Kylheku, Feb 18, 2014
    #11
  12. Melzzzzz

    James Kuyper Guest

    Of course it was put there to be taken advantage of. That doesn't mean
    it was a good decision to put it there, nor that it's a good idea to
    take advantage of the fact that it was put there.

    My only objection to people using "void main()" is the fact that the
    standard doesn't guarantee that it is supported. I don't favor adding
    "void main()" as signature that implementations are required to support,
    but neither am I opposed to it. If the committee wanted to cater to
    those who don't want to be bothered returning a value from main(), then
    it should have allowed this only if main() is declared as returning void.

    Having a function declared as returning a value, where use of that value
    to determine the exit status returned to the host environment is
    mandated by the standard, and then allowing it to return without
    specifying a return value, was just plain wrong.
     
    James Kuyper, Feb 19, 2014
    #12
  13. Melzzzzz

    Kaz Kylheku Guest

    The implicit successful return from main was probably not put there to be taken
    advantage of. It was probably put there to fix the misbehaving termination
    status of legacy programs which do that, and which are never going to be
    fixed with a "return 0", but which might be recompiled with C99.

    This was a poor idea in itself; changing the behavior of unknown amounts of
    code. As Kenny observed, programs out there may be relying (whether
    by intent or accident) on the behavior that the return value of an int function
    in the tail position of main is propagated.

    (And if you're going to cave in to poor programming, why not "bless"
    void main also while you're at it ...)
     
    Kaz Kylheku, Feb 19, 2014
    #13
  14. Melzzzzz

    alpha Guest

    I am really puzzled that I have to
    return from main.
    main.c:
    int main(void)
    {
    }

    bmaxa@maxa:~/examples$ gcc -Wall main.c
    main.c: In function 'main':
    main.c:3:1: warning: control reaches end of non-void function
    [-Wreturn-type]
    }
    ^
    bmaxa@maxa:~/examples$ clang -Wall main.c
    bmaxa@maxa:~/examples$ icc -Wall main.c
    bmaxa@maxa:~/examples$

    Of three C compilers that I use, only gcc gives warning. What does
    it means? Is it something new or was always like that?

    --
    Click OK to continue...


    Isnt the short and simple answer that main() declared to return an integer
    value is missing
    said return value in the brackets ? For example {return 0;} would fix the
    warning.
    Since the other 2 compiler dont return a warning the authors must have
    followed
    a different standard. Just my 2 cents
     
    alpha, Feb 21, 2014
    #14
  15. Melzzzzz

    James Kuyper Guest

    On 02/21/2014 12:52 AM, Robert Wessel wrote:
    ....
    Can you cite the text that provides a special dispensation for main() in
    C89? I don't have a copy of that standard, but my understanding is that
    there was no such special dispensation until C99.
     
    James Kuyper, Feb 21, 2014
    #15
  16. Heh heh. And you claim that clc is not motivated by the same sorts of
    impulses as motivate religion...?

    --
    Here's a simple test for Fox viewers:

    1) Sit back, close your eyes, and think (Yes, I know that's hard for you).
    2) Think about and imagine all of your ridiculous fantasies about Barack Obama.
    3) Now, imagine that he is white. Cogitate on how absurd your fantasies
    seem now.

    See? That wasn't hard, was it?
     
    Kenny McCormack, Feb 21, 2014
    #16
  17. "If the main function executes a return that specifies no value, the
    termination status returned to the host environment is undefined."

    Right at the end on 2.1.2.2
    http://www.bsb.me.uk/ansi-c/ansi-c-one-file.html#sec_2_1_2_2
     
    Ben Bacarisse, Feb 21, 2014
    #17
  18. Melzzzzz

    Seebs Guest

    I *think*, although I'm not sure, that the reason Something Had To Be Done
    is that this doesn't make any sense; *behavior* can be undefined, but a
    termination status... well, that's weird, what can it be? It could be
    unspecified, probably, but it may be that you want to indicate that
    something could go horribly wrong, in which case you'd be saying that the
    behavior was undefined. But that seems undesireable, and no one knows of
    an implementation which actually explodes.

    My memory's sort of vague, it's been >15 years now.

    -s
     
    Seebs, Feb 24, 2014
    #18
  19. Melzzzzz

    Kaz Kylheku Guest

    The obvious fix is "the termination status is indeterminate", regarding it
    as a kind of value that the program can produce, but which doesn't
    have a C type, being an abstraction with the domain values "successful",
    "failed" and possibly other.
    If it's unspecified, then there has to be some set of alternatives from
    among which the implementation makes an undocumented choice.
    Undefined behavior isn't only "something could go horribly wrong".

    Undefined behavior is also such stuff as including <unistd.h> or calling fcntl.

    Undefined behavior upon main falling out without a return value is fine;
    implementors could work at detecting the situation, and convert it to
    a successful status, as an extension. (The same way they have to since C99,
    to provide required behavior.)
    Many implementations also do not explode when an int-returning function
    that neglects to return anything is called, and its return value is retrieved.

    In many of those implementation which don't explode when main neglects
    to return a value, main is actually returning to some other function, and
    not directly to the OS. So that isn't blowing up either.

    Also, many implementations do not explode when the blasphemous void main is
    used, the recognition of whose undefinedness is a rite of passage around
    here.
     
    Kaz Kylheku, Feb 24, 2014
    #19
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.