Hello World! Slashdot style



  • I've been thinking of formulating a new law of the internet: whenever someone attempts to write "Hello World!" in an online forum, they resulting code will always have at least one bug. Take this recent Slashdot example of a "bug free" example:

    #include <stdio.h>
    int main()
    {
    return printf("Hello world\n");
    }

    There is a potential corollary that the thread will then dissolve into a discussion about how wrong the example is.

     



  • What's the bug? Maybe I'm being daft, but I can't spot it. And it compiles and runs fine...



  • @RichardNeill said:

    What's the bug? Maybe I'm being daft, but I can't spot it. And it compiles and runs fine...

    I'm wondering whether to point it out or to let TDWTF work it out :)
     



  • Worst I can see is that it's supposed to return an int, but instead returns whatever printf returns (self taught C, so I dunno, is it a string, bool, int?).

     Edit: Nah, printf returns an int according to Visual C++. And it compiles and runs fine for me with the addition of

    #include "stdafx.h"


     



  • I suppose the worst thing you can say is that the return value is unconventional - usually 0 is returned for success, but printf() returns the number of characters outputted.  Apparently.

     

    Right? 



  • @Tibby Lickle said:

    I suppose the worst thing you can say is that the return value is unconventional - usually 0 is returned for success, but printf() returns the number of characters outputted.  Apparently.

    Pretty much. printf() will return the number of characters written or a negative value if an error occurs. The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.

    The WTF is not so much that one example: the WTF was that this was posted as an example of how easy it is to write scalable bug free code, handily proving the complete opposite. It's actually very hard to write even the most simple application and not to have any bugs or potential bugs. I also still think my proposed new law has merit :)
     



  • @Vanders said:

    @Tibby Lickle said:

    I suppose the worst thing you can say is that the return value is unconventional - usually 0 is returned for success, but printf() returns the number of characters outputted.  Apparently.

    Pretty much. printf() will return the number of characters written or a negative value if an error occurs. The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.

     

    Which only goes to show that in order to do anything useful, you need to narrow your goals more. "Portable to any C implementation" is about as useful as "portable to run on any computer and also on my underpants", and about half as practical. The language and platform specs are useful, but an application written to the specs is an application that doesn't work on any actual systems.



  • @asuffield said:

    Which only goes to show that in order to do anything useful, you need to narrow your goals more. "Portable to any C implementation" is about as useful as "portable to run on any computer and also on my underpants", and about half as practical. The language and platform specs are useful, but an application written to the specs is an application that doesn't work on any actual systems.

     I agree with your general sentiment, but in this particular instance I think it's more a case of being aware of the limitations of your tools and when and how they apply. In this particular case it doesn't even apply: Hello World! is an obvious contrived case where you're not expecting to produce a useful application. Anyone familiar enough with a language to claim competency should be able to write a Hello World! without introducing bugs, or at least they should be aware of where they have cut corners and bugs may be possible.
     



  • @Vanders said:

    @Tibby Lickle said:

    I suppose the worst thing you can say is that the return value is unconventional - usually 0 is returned for success, but printf() returns the number of characters outputted.  Apparently.

    Pretty much. printf() will return the number of characters written or a negative value if an error occurs. The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.

    I think you're stretching the point a bit here.  That's not "a bug", that's "invoking implementation-defined behaviour".  Both the C language standard and the Opengroup POSIX spec permit you to return any integer value from main (or via exit(), which is equivalent), and the only implementation-defined part of it is how this may translate into a success or failure status being returned to "the host environment".  If your design spec for "hello world" doesn't impose any requirement about the status returned, the program complies perfectly. 

    Seriously, who cares about the exit status from "Hello world"?

     

    #!/bin/bash 

    ./hello && < do stuff here which critically depends on the success of hello world >

    I can't see it!

     



  • See also Hello World, cut four ways AKA "The worst possible Hello World"



  • I aggree with Vanders is this case. If the hello-world-program is meant as an example for "scalable bug free code", it's a failure. "Works in almost all cases and environments" is not enough if you need "scalable bug free code". Code like that is a timebomb waiting for "but it worked on my box...".
     



  • @Vanders said:

    I've been thinking of formulating a new law of the internet: whenever someone attempts to write "Hello World!" in an online forum, they resulting code will always have at least one bug. Take this recent Slashdot example of a "bug free" example:

    #include <stdio.h>
    int main()
    {
    return printf("Hello world\n");
    }

    There is a potential corollary that the thread will then dissolve into a discussion about how wrong the example is.

     

    I suppose the requirements might be a bit lax on punctuation, case-sensitivity, and the like, but the one thing that this little gem doesn't do is to print out:

    Hello World! 



  • @ammoQ said:

    I aggree with Vanders is this case. If the hello-world-program is meant as an example for "scalable bug free code", it's a failure. "Works in almost all cases and environments" is not enough if you need "scalable bug free code". Code like that is a timebomb waiting for "but it worked on my box...".
     

    But that's simply not the case.  The code is correct, conformant and valid, and works in absolutely all cases and environments.  You are free to return any integer value you like from main.


     




  • @Daniel Beardsmore said:

    See also Hello World, cut four ways AKA "The worst possible Hello World"

    Funny, but not entirely correct.  His analysis of the 'canonical' hello world says:

    [quote user="Hello World, cut four ways"]

    • The argument list to main was not specified. This isn't a big problem, because when you're defining a function (as opposed to declaring it, leaving it to be defined later or elsewhere), leaving the argument list empty is the same as saying void (i.e. no arguments). But it's bad form to let the compiler guess — you're writing the program; be thorough.

    [/quote]

    It isn't a big problem, it isn't any kind of problem at all, because both C and C++ specifically permit main with no args.  His complaint doesn't really make any sense; as he says, leaving the argument list empty is the same as specifying void explicitly, so in what on earth sense of the word are you leaving the compiler to "guess" anything?

    [quote user="Hello World, cut four ways"]

    • Bad use of printf. More on this later.

    [/quote]

    Well, I can't argue that printf isn't overkill, but this is just picky.  So it's suboptimal?  So puts is quicker by many microseconds?  So how many millions of times a day do you expect to run this hello world program?  Because you'd need to run it millions of times before the use of printf instead of puts cost you as much as a few seconds.  Premature optimisation is A Bad Thing, and this is premature micro-optimisation.  The compiler will substitute puts for printf for you when it sees a constant format string containing no format specifiers; the programmer should leave it to do the heavy lifting and fiddly details.

    [quote user="Hello World, cut four ways"]

    • Failure to return a value. main is typed as returning an int, but there is no return statement. The compiler might fill in a return 0; for you, but you shouldn't rely on this. Again, be thorough. Return zero yourself.

    [/quote]

    The compiler absolutely will fill in a return 0; for you, or the compiler is buggy.  Again, the C language standard explicitly says this is ok.

    @n2794 C language spec said:

    5.1.2.2.1 Program  startup
    1 The function called at program startup is named main. The implementation declares no
    prototype for this function. It shall be defined with a return type of int and with no
    parameters:
    int main(void) { /* ... */ }
    or with two parameters (referred to here as argc and argv, though any names may be
    used, as they are local to the function in which they are declared):
    int main(int argc, char *argv[]) { /* ... */ }
    or equivalent; or in some other implementation-defined manner.

    @n2794 C language spec said:

    5.1.2.2.3 Program  termination
    If the return type of the main function is a type compatible with int, a return from the
    initial call to the main function is equivalent to calling the exit function with the value
    returned by the main function as its argument; reaching the } that terminates the main
    function returns a value of 0. If the return type is not compatible with int, the
    termination status returned to the host environment is unspecified.

      Oh, and here's the bit about return values allowed:
    @n2794 C language spec said:

    7.20.4.3 The exit function
    Synopsis
    1 #include <stdlib.h>
    void exit(int status);
    Description
    2 The exit function causes normal program termination to occur. If more than one call to
    the exit function is executed by a program, the behavior is undefined.
    3 First, all functions registered by the atexit function are called, in the reverse order of
    their registration.
    4 Next, all open streams with unwritten buffered data are flushed, all open streams are
    closed, and all files created by the tmpfile function are removed.
    5 Finally, control is returned to the host environment.  If the value of status is zero or
    EXIT_SUCCESS, an implementation-defined form of the status successful termination is
    returned.  If the value of status is EXIT_FAILURE, an implementation-defined form
    of the status unsuccessful termination is returned. Otherwise the status returned is
    implementation-defined.
    Returns
    6 The exit function cannot return to its caller.

    Still, I like his thoroughness in adding error checking though, it's a really good point: you really should check your return values every single time, even if there's nothing you can do about it but report the error to the user and fail.

     



  • @DaveK said:

    [quote user="Hello World, cut four ways"]

    • The argument list to main was not
      specified. This isn't a big problem, because when you're defining a
      function (as opposed to declaring it, leaving it to be defined later or
      elsewhere), leaving the argument list empty is the same as saying void (i.e. no arguments). But it's bad form to let the compiler guess — you're writing the program; be thorough.

    It isn't a big problem, it isn't any kind of problem at all, because both C and C++ specifically permit main with no args.  His complaint doesn't really make any sense; as he says, leaving the argument list empty is the same as specifying void explicitly, so in what on earth sense of the word are you leaving the compiler to "guess" anything?

    [/quote]

    Hrngh!

    In C++, int foo() is the same as int foo(void), in all contexts.

    In C, int foo() {} is the same as int foo(...) {} - which is to say, a definition of a stdarg-type variadic function.

    However, in C, the line:

    int foo();

    is not a prototype. It declares 'foo' as a function, but does not assign a type to it. This is why it is important to never write that in C. In a declaration (rather than a definition), you should always write (void) or (...) explicitly, so that the compiler can type-check your code.

    This is historical crap for compatibility with K&R C. There is no good reason for using it. 



  • @DaveK said:

    Still, I like his thoroughness in adding error checking though, it's a really good point: you really should check your return values every single time, even if there's nothing you can do about it but report the error to the user and fail.

    Sure, but how on earth would your code look if you always checked for error codes from malloc / fprintf etc? It would look abolutely and absurdly convoluted. So my strong opinion is that this is only to be done if there is a strong reason to believe that the operation might fail during normal use of the app. This is certainly not appropriate in the example above.



  • Addendum: I realize that this would mean that errors could be silently ignored,
    which is of course bad, and is also why a proper exception handling
    system comes in handy.



  • See also Hello World, cut four ways AKA "The worst possible Hello World"

    If we're going to be pedantic, let's do it right. He didn't check the return value from fprintf(stderr,...) to make sure that the output was successful. FAIL.



  • @Obfuscator said:

    @DaveK said:

    Still, I like his thoroughness in adding error checking though, it's a really good point: you really should check your return values every single time, even if there's nothing you can do about it but report the error to the user and fail.

    Sure, but how on earth would your code look if you always checked for error codes from malloc / fprintf etc?

    #include <stdio.h>

    void report_error(char *msg);

    int main(void) {
      int r;
      r = printf("Hello World!\n");
      if (r<0) {
        report_error("Cannot output hello world!!!");
      }

      return 0;
    }

    void report_error(char msg) {
      int r;
      r = fprintf(stderr, "%s", msg);
      if (r<0) {
        report_error("Cannot output error message!!!");  /
    for some reason I haven't found out yet, the program never outputs the error message... it just hangs or crashes with a stack overflow... must be a bug in the compiler or standard lib */
      }
    }



  • void report_error(char *msg)
    {
    if ( log_to_database(msg) < 0 )
    {
    if ( log_to_file(msg) < 0 )
    {
    if ( log_to_syslog(msg) < 0 )
    {
    if ( send_by_email(msg) < 0 )
    {
    if ( send_to_printer(msg) < 0 )
    {
    if ( morse_code_on_pc_speaker(msg) < 0 )
    {
    if ( morse_code_on_hd_light(msg) < 0 )
    {
    if ( telepathically_contact_user(msg) < 0 )
    {
    if ( pray_to_deity(msg) < 0 )
    {
    if ( overload_cpu_and_selfdestruct() < 0 )
    {
    exit 1; // let the caller handle it
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }


  • @Sunstorm said:

    void report_error(char *msg)
    {
    if ( log_to_database(msg) < 0 )
    {
    if ( log_to_file(msg) < 0 )
    {
    if ( log_to_syslog(msg) < 0 )
    {
    if ( send_by_email(msg) < 0 )
    {
    if ( send_to_printer(msg) < 0 )
    {
    if ( morse_code_on_pc_speaker(msg) < 0 )
    {
    if ( morse_code_on_hd_light(msg) < 0 )
    {
    if ( telepathically_contact_user(msg) < 0 )
    {
    if ( pray_to_deity(msg) < 0 )
    {
    if ( overload_cpu_and_selfdestruct() < 0 )
    {
    exit 1; // let the caller handle it
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }

    void report_error(char *msg)
      if ( log_to_database(msg) == 0 )
        return;
      if ( log_to_file(msg) == 0 )
        return;
      ...
    }
    

    smack



  • @asuffield said:

    void report_error(char *msg)
    if ( log_to_database(msg) == 0 )
    return;
    if ( log_to_file(msg) == 0 )
    return;
    ...
    }

    smack

    #define ZEROLOG_TO_DATABASE 0
    #define ONELOG_TO_FILE 1
    ...

    void report_error(char *msg)  {
      int i,r;
      for (i=0; i<=NINELOG_LAST; i++) {
        switch(i) {
           case ZEROLOG_TO_DATABASE: r=log_to_database(msg); break;
           case ONELOG_TO_FILE: r=log_to_database(msg); break;
    ...
        }
        if (r==0) return;
      }
    }
     



  • @ammoQ said:

    @Obfuscator said:
    @DaveK said:

    Still, I like his thoroughness in adding error checking though, it's a really good point: you really should check your return values every single time, even if there's nothing you can do about it but report the error to the user and fail.

    Sure, but how on earth would your code look if you always checked for error codes from malloc / fprintf etc?

    #include <stdio.h>

    void report_error(char *msg);

    int main(void) {
      int r;
      r = printf("Hello World!\n");
      if (r<0) {
        report_error("Cannot output hello world!!!");
      }

      return 0;
    }

    void report_error(char msg) {
      int r;
      r = fprintf(stderr, "%s", msg);
      if (r<0) {
        report_error("Cannot output error message!!!");  /
    for some reason I haven't found out yet, the program never outputs the error message... it just hangs or crashes with a stack overflow... must be a bug in the compiler or standard lib */
      }
    }

    void report_error(char msg) {

    int n = strlen(msg); 

    int r = write(2,msg,n);

    if(r != n) / well, either (A) something's gone horribly wrong, or (B) we've somehow closed stderr [see also (A)] */;

    }

    (properly, i should be looping to try to print the rest, if r is positive but not n.)



  • @DaveK said:

    @Vanders said:

    @Tibby Lickle said:

    I suppose the worst thing you can say is that the return value is unconventional - usually 0 is returned for success, but printf() returns the number of characters outputted.  Apparently.

    Pretty much. printf() will return the number of characters written or a negative value if an error occurs. The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.

    I think you're stretching the point a bit here.  That's not "a bug", that's "invoking implementation-defined behaviour".  Both the C language standard and the Opengroup POSIX spec permit you to return any integer value from main (or via exit(), which is equivalent), and the only implementation-defined part of it is how this may translate into a success or failure status being returned to "the host environment".  If your design spec for "hello world" doesn't impose any requirement about the status returned, the program complies perfectly. 

    Seriously, who cares about the exit status from "Hello world"?

     

    #!/bin/bash 

    ./hello && < do stuff here which critically depends on the success of hello world >

    I can't see it!

    What about the corrolary case:

    ./goodbyeWorld && ./suicideWasPainless && ./deathWasSuccessful > theEnd.log

     



  • @ammoQ said:

    @asuffield said:
    void report_error(char *msg)
    if ( log_to_database(msg) == 0 )
    return;
    if ( log_to_file(msg) == 0 )
    return;
    ...
    }

    *smack*

    #define ZEROLOG_TO_DATABASE 0
    #define ONELOG_TO_FILE 1
    ...

    void report_error(char *msg)  {
      int i,r;
      for (i=0; i<=NINELOG_LAST; i++) {
        switch(i) {
           case ZEROLOG_TO_DATABASE: r=log_to_database(msg); break;
           case ONELOG_TO_FILE: r=log_to_database(msg); break;
    ...
        }
        if (r==0) return;
      }
    }
     

    How about:
    <font color="#00ff00">int</font> (*error_func[])(<font color="#00ff00">char</font>*) = {
                            log_to_database,
                            log_to_file,
                            log_to_syslog,
                            send_by_email,
                            send_to_printer,
                            morse_code_on_pc_speaker,
                            <font color="#ff6060">NULL</font>
                            };
    <font color="#00ff00">void</font> report_error (<font color="#00ff00">char</font>* msg)
    {
            <font color="#00ff00">int</font> i = <font color="#ff6060">0</font>;
            <font color="#0000ff">while</font>(error_func[i])
                    <font color="#0000ff">if</font>(error_func[i](msg))
                            <font color="#0000ff">return</font>;
            exit(<font color="#ff6060">1</font>);
    }
    


  • @random_garbage said:

    How about:

    <font color="#00ff00">int</font> (*error_func[])(<font color="#00ff00">char</font>*) = {
    log_to_database,
    log_to_file,
    log_to_syslog,
    send_by_email,
    send_to_printer,
    morse_code_on_pc_speaker,
    <font color="#ff6060">NULL</font>
    };
    <font color="#00ff00">void</font> report_error (<font color="#00ff00">char</font>* msg)
    {
    <font color="#00ff00">int</font> i = <font color="#ff6060">0</font>;
    <font color="#0000ff">while</font>(error_func[i])
    <font color="#0000ff">if</font>(error_func[i](msg))
    <font color="#0000ff">return</font>;
    exit(<font color="#ff6060">1</font>);
    }

    Add "==0" or "!" in the "if" statement and it might actually even make sense. 



  • @ammoQ said:

    Add "==0" or "!" in the "if" statement and it might actually even make sense. 

    D'oh! 

    Hey, I should claim that that was an intentional bug, to prove the point in the OP... Yeah, that was it, totally. *looks around anxiously*



  • If nothing else, this thread seems to support the corollary!



  • A switch will make things so much nicer.

    switch (1) {
       case log_to_database(msg):
       case log_to_file(msg):
       case log_to_syslog(msg):
       case send_by_email(msg):
       case send_to_printer(msg):
       case morse_code_on_pc_speaker(msg):
       case morse_code_on_hd_light(msg):
       case telepathically_contact_user(msg):
       case pray_to_deity(msg):
       case overload_cpu_and_selfdestruct():
       break;
       default: exit 1;
    }


  • @ammoQ said:

    void report_error(char msg) {
      int r;
      r = fprintf(stderr, "%s", msg);
      if (r<0) {
        report_error("Cannot output error message!!!");  /
    for some reason I haven't found out yet, the program never outputs the error message... it just hangs or crashes with a stack overflow... must be a bug in the compiler or standard lib */
      }
    }

    @Sunstorm said:

    morse_code_on_hd_light(msg)

     

    @Sunstorm said:

    exit 1; // let the caller handle it


     Now that's real humor! Lemme try that in lolcode:

    HAI

    CAN HAS STDIO?

    AWSUM THX

        VISIBLE "Hello world" PLZ

            AWSUM THX PASS

             O NOES

                VISIBLE "Hello world" ON COMPY FRONT LED THINGY PLZ?

                    AWSUM THX PASS
                    O NOES

                        LEMME GET OUTTA HERE -1 

    O NOES

       HAI AGAIN


     

     



  • @ammoQ said:

      r = fprintf(stderr, "%s", msg);

      if (r<0) {

        report_error("Cannot output error message!!!");  /* for some reason I haven't found out yet, the program never outputs the error message... it just hangs or crashes with a stack overflow... must be a bug in the compiler or standard lib */

    I imagine that I am far from alone in having seen this happen for real. ShadowIRC on the Mac out of memory and trying to report that it was out of memory with a dialog box ...



  • @Daniel Beardsmore said:

    @ammoQ said:
      r = fprintf(stderr, "%s", msg);
      if (r<0) {
        report_error("Cannot output error message!!!");  /* for some reason I haven't found out yet, the program never outputs the error message... it just hangs or crashes with a stack overflow... must be a bug in the compiler or standard lib */

    I imagine that I am far from alone in having seen this happen for real. ShadowIRC on the Mac out of memory and trying to report that it was out of memory with a dialog box ...

    I've seen this kind of error in the real world, too. The Real WTF(tm) in that case was that it didn't take much to trigger the error, being unable to reach a certain server during startup of the program was enough.



  • I imagine that I am far from alone in having seen this happen for real. ShadowIRC on the Mac out of memory and trying to report that it was out of memory with a dialog box ...

    To be fair, I have no idea how would one go about notifying the user about being out of memory. Maybe the program could tear itself down to try freeing memory, and then try notifying? I can't really imagine most programs going through the effort.

     

    And come to think of it, using the PC speaker to voice-synth the message instead of morse code would be much more user-friendly. A project!



  • @Sunstorm said:

    And come to think of it, using the PC speaker to voice-synth the message instead of morse code would be much more user-friendly. A project!

    The default behaviour of Mac OS 8 and 9 is scarily close to this. If you do not acknowledge an alert dialog box within a given number of seconds, the computer will read it out aloud to you. Normally it doesn't serve any purpose, but it came in handy when experimenting with Jazz Jackrabbit to try getting it to run with out-of-range screen modes. This would cause the game to crash and the OS would leave the screen completely empty and grey. I thought the OS itself had been taken out, and was pressing reset, but then I left it long enough to hear it read out "The application "Jazz Jackrabbit 2™ demo" has unexpectedly quit…" and realised that if I pressed enter, and loaded the game again, and closed it early, it would put all my colours back on clean exit.

    Normally, though, I get rid of voice error reporting. Before it gets to, "Sorry, I can't do that Dan..."



  • @Sunstorm said:

    I imagine that I am far from alone in having seen this happen for real. ShadowIRC on the Mac out of memory and trying to report that it was out of memory with a dialog box ...

    To be fair, I have no idea how would one go about notifying the user about being out of memory. Maybe the program could tear itself down to try freeing memory, and then try notifying? I can't really imagine most programs going through the effort.

    The program I'm working on has code to deal with exactly this situation: it allocates a 64K block of memory when it starts up. If an allocation ever fails, it cancels any pending operations, frees the 64k block (to give the OS something to work with), and notifies the user.

    Keep in mind that this part of the code was written back when computers typically had 4MB or so of RAM, and 64k wasn't smaller than the minimum allocation block for any of the OSs the program was intended to run on.



  • @Carnildo said:

    @Sunstorm said:

    I imagine that I am far from alone in having seen this happen for real. ShadowIRC on the Mac out of memory and trying to report that it was out of memory with a dialog box ...

    To be fair, I have no idea how would one go about notifying the user about being out of memory. Maybe the program could tear itself down to try freeing memory, and then try notifying? I can't really imagine most programs going through the effort.

    The program I'm working on has code to deal with exactly this situation: it allocates a 64K block of memory when it starts up. If an allocation ever fails, it cancels any pending operations, frees the 64k block (to give the OS something to work with), and notifies the user.

    Waste of time these days. Any modern operating system will look at your request for 64k, say "okay, whatever", and ignore it. No actual memory will be allocated until it is needed. A valid return from malloc() does not guarantee memory allocation, and except in very unusual circumstances (like running out of virtual address space, or hitting your rlimit) malloc() will never fail. If memory allocation does fail, the system just kills off processes until there's some memory free again.



  • @Sunstorm said:

    To be fair, I have no idea how would one go about notifying the user about being out of memory. Maybe the program could tear itself down to try freeing memory, and then try notifying? I can't really imagine most programs going through the effort.

    Windows at least has a solution for this one... if you bring up a message box with the "Error icon" and "System Modal" flags set, it'll always succeed even if there's no memory available - all the memory needed for the message box is pre-allocated when windows starts, and a lot of the processing that Windows normally does on message boxes is disabled (no word wrap, message must be at most 3 lines long).

    So I've got this code in most of my programs:

    void * malloc_or_die (size_t n)
    {
      void *ptr = malloc(n);
      if (!ptr)
      {
        MessageBox(NULL, "Out of memory.", "Error", MB_ICONHAND | MB_SYSTEMMODAL);
        exit(1);
      }
      return ptr;
    }

    It wouldn't surprise me if the Mac had something similar.



  • @Vanders said:

    The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.


    Technically, you're only supposed to use EXIT_SUCCESS and EXIT_FAILURE, as not every imaginable system must use 0 for EXIT_SUCCESS. (despite the fact that they all do...)



  • @Vanders said:

    The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.

    #define EXIT_FILENOTFOUND  0

     

     



  • @asuffield said:

    If memory allocation does fail, the system just kills off processes until there's some memory free again.

    WHAT!?!?!? No operating system should do that. It's about the worst possible behaviour. Priority for memory should be given to those processes which already have it. It shouldn't just kill off processes at random, that could be disastrous. Suppose your *sqld on the database server is close to maxed the memory, and then some fool walks up to it and starts a game. Do you want the OS to kill *sqld? NO!



  • @m0ffx said:

    WHAT!?!?!? No operating system should do that. It's about the worst possible behaviour. Priority for memory should be given to those processes which already have it. It shouldn't just kill off processes at random, that could be disastrous. Suppose your *sqld on the database server is close to maxed the memory, and then some fool walks up to it and starts a game. Do you want the OS to kill *sqld? NO!

    Well, I mean, you'll have a much better framerate without that pesky sql server running in the background... 



  • @m0ffx said:

    @asuffield said:

    If memory allocation does fail, the system just kills off processes until there's some memory free again.

    WHAT!?!?!? No operating system should do that. It's about the worst possible behaviour. Priority for memory should be given to those processes which already have it. It shouldn't just kill off processes at random, that could be disastrous. Suppose your *sqld on the database server is close to maxed the memory, and then some fool walks up to it and starts a game. Do you want the OS to kill *sqld? NO!

    Nobody ever accused any of the major operating systems of not sucking. The best one on this particular point at present is Linux, which at least has some intelligence about which process to kill, and you have the option to disable this behaviour entirely (if you know what you're doing).

    Overcommitting became common practice several years ago, when people kept writing applications that allocated craploads of memory that they never used. 



  • @joemck said:

    @Vanders said:
    The only valid portable return values from main() are 0, EXIT_SUCCESS or EXIT_FAILURE.

    Technically, you're only supposed to use EXIT_SUCCESS and EXIT_FAILURE, as not every imaginable system must use 0 for EXIT_SUCCESS. (despite the fact that they all do...)

    No, 0 is valid. As someone else kindly quoted from the C specification:

     

    7.20.4.3 The exit function
    Synopsis
    1 #include <stdlib.h>
    void exit(int status);
    Description
    2 The exit function causes normal program termination to occur. If more than one call to
    the exit function is executed by a program, the behavior is undefined.
    3 First, all functions registered by the atexit function are called, in the reverse order of
    their registration.
    4 Next, all open streams with unwritten buffered data are flushed, all open streams are
    closed, and all files created by the tmpfile function are removed.
    5 Finally, control is returned to the host environment.  If the value of status is zero or
    EXIT_SUCCESS, an implementation-defined form of the status successful termination is
    returned.  If the value of status is EXIT_FAILURE, an implementation-defined form
    of the status unsuccessful termination is returned. Otherwise the status returned is
    implementation-defined.
    Returns
    6 The exit function cannot return to its caller. 

    #5 is the important bit. 



  • @m0ffx said:

    @asuffield said:

    If memory allocation does fail, the system just kills off processes until there's some memory free again.

    WHAT!?!?!? No operating system should do that. It's about the worst possible behaviour. Priority for memory should be given to those processes which already have it. It shouldn't just kill off processes at random, that could be disastrous. Suppose your *sqld on the database server is close to maxed the memory, and then some fool walks up to it and starts a game. Do you want the OS to kill *sqld? NO!

    You seem to be under the misapprehension that asuffield is making a suggestion, rather than reporting facts. Specifically, it is linux that does this.



  • @Vanders said:

    If the value of status is zero or EXIT_SUCCESS, an implementation-defined ... is returned.  If the value of status is EXIT_FAILURE, an implementation-defined ... is returned. Otherwise the status returned is implementation-defined.

    So, when is it not implementation-defined?



  • @Random832 said:

    @Vanders said:

    If the value of status is zero or EXIT_SUCCESS, an implementation-defined ... is returned.  If the value of status is EXIT_FAILURE, an implementation-defined ... is returned. Otherwise the status returned is implementation-defined.

    So, when is it not implementation-defined?

    You've cut the important bits from the quote. When exit() is called with 0 OR EXIT_SUCCESS, the implementation should inform the system that the application has exited successfully. When exit() is called with EXIT_FAILURE, the implementation should inform the system that the application has exited but something was wrong. If exit() is called with any other value besides, 0, EXIT_SUCCESS or EXIT_FAILURE, it's upto the implementation (& the system) what happens: maybe calling exit() with a value of 461 will cause all of your user processes to be suspended? The standard doesn't say.


Log in to reply