what is the output of this program?

Discussion in 'C Programming' started by Kenny O'Clock, May 28, 2008.

  1. This came up in a job interview, what is the output of the program
    below? I tried to compile and run it myself, but my compiler (lcc-win32)
    aborts with this errors....

    Warning test2.c: 3 old-style function definition for 'main'
    Warning test2.c: 3 missing prototype for 'main'
    Warning test2.c: 3 '
    Error test2.c: 3 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
    Error c:\test\test2.c 3 Compiler error (trap). Stopping compilation
    1 error

    Here is the program....

    1: #include <stdio.h>
    2: void main()
    3: {
    4: int C = 0;
    5: printf("C %s C++\n", C == C++ ? "==" : "!=");
    6: }

    I don't even have a d:\lcc\mc71\ folder on my computer!
    Please help, I don't know what to do anymore!!!
     
    Kenny O'Clock, May 28, 2008
    #1
    1. Advertising

  2. In article <>,
    Kenny O'Clock <> wrote:

    >This came up in a job interview, what is the output of the program
    >below?


    > 1: #include <stdio.h>
    > 2: void main()
    > 3: {
    > 4: int C = 0;
    > 5: printf("C %s C++\n", C == C++ ? "==" : "!=");
    > 6: }


    In the expression C == C++,
    the variable being incremented is accessed more than once between
    sequence points ("except to determine the value to be stored").
    That is not permitted, so the result could be anything.
    -Usually- the result would be either "C == C++" or "C != C++"
    printed out (dependant on the compiler), but the program
    could segfault... or, like you found, the -compiler- could fault.
    --
    "And that's the way it is." -- Walter Cronkite
     
    Walter Roberson, May 29, 2008
    #2
    1. Advertising

  3. In article <>,
    Pietro Cerutti <gahr_SPAM_gahr_ME_ch> wrote:
    >Kenny O'Clock wrote:


    >> 5: printf("C %s C++\n", C == C++ ? "==" : "!=");


    >In addition to what Walter said, I would like to point you to question
    >3.2 of the c.l.c FAQ, at http://c-faq.com/expr/evalorder2.html.


    Though the impact of that question is a bit reduced because there -is-
    a sequence point after the evaluation of C == C++ . That confines
    the section of undefined behaviour to be relatively small compared
    to typical expressions we see that mix variable accesses with
    ++ or -- .
    --
    "Nothing recedes like success." -- Walter Winchell
     
    Walter Roberson, May 29, 2008
    #3
  4. Kenny O'Clock

    Guest

    In article <g1l7jg$aln$>,
    Walter Roberson <-cnrc.gc.ca> wrote:
    >In article <>,
    >Pietro Cerutti <gahr_SPAM_gahr_ME_ch> wrote:
    >>Kenny O'Clock wrote:

    >
    >>> 5: printf("C %s C++\n", C == C++ ? "==" : "!=");

    >
    >>In addition to what Walter said, I would like to point you to question
    >>3.2 of the c.l.c FAQ, at http://c-faq.com/expr/evalorder2.html.

    >
    >Though the impact of that question is a bit reduced because there -is-
    >a sequence point after the evaluation of C == C++ . That confines
    >the section of undefined behaviour to be relatively small compared
    >to typical expressions we see that mix variable accesses with
    >++ or -- .


    Relatively small, perhaps, but still large enough to include all of the
    accesses to C in that line of code.


    dave

    --
    Dave Vandervies dj3vande at eskimo dot com
    My burning question is this:
    "Why do you have some perverse desire to lie to fprintf()?"
    --Dann Corbit in comp.lang.c
     
    , May 29, 2008
    #4
  5. Richard Heathfield wrote:
    > Walter Roberson said:
    >
    >> In article <>,
    >> Pietro Cerutti <gahr_SPAM_gahr_ME_ch> wrote:
    >>> Kenny O'Clock wrote:

    >>
    >>>> 5: printf("C %s C++\n", C == C++ ? "==" : "!=");

    >>
    >>> In addition to what Walter said, I would like to point you to
    >>> question
    >>> 3.2 of the c.l.c FAQ, at http://c-faq.com/expr/evalorder2.html.

    >>
    >> Though the impact of that question is a bit reduced because there
    >> -is- a sequence point after the evaluation of C == C++ . That
    >> confines
    >> the section of undefined behaviour to be relatively small compared
    >> to typical expressions we see that mix variable accesses with
    >> ++ or -- .

    >
    > Firstly, because the Standard imposes no limits on the implementation
    > with regard to undefined behaviour, the wayward effect of C == C++ is
    > not limited to the "section" of code within which it occurs.
    >
    > Secondly (and I only mention it because nobody else has in the five
    > replies that I've seen), the program exhibits undefined behaviour in
    > another way, too, because the return type of main is incorrect.

    And win-lcc properly warns about this...

    Bye, Jojo
     
    Joachim Schmitz, May 29, 2008
    #5
  6. Kenny O'Clock

    Dan Guest


    > I don't even have a d:\lcc\mc71\ folder on my computer!
    > Please help, I don't know what to do anymore!!!


    I give questions like that just to seperate who is anal and who isn't (and
    don't employ the anal ones - they are most likly to take 10 times as long to
    write the same page code that no one is ever going to read again).
    And just incase you really are dumb, C is not equal to C++.
     
    Dan, May 29, 2008
    #6
  7. Kenny O'Clock

    Richard Guest

    "Dan" <> writes:

    >> I don't even have a d:\lcc\mc71\ folder on my computer!
    >> Please help, I don't know what to do anymore!!!

    >
    > I give questions like that just to seperate who is anal and who isn't (and
    > don't employ the anal ones - they are most likly to take 10 times as long to
    > write the same page code that no one is ever going to read again).
    > And just incase you really are dumb, C is not equal to C++.


    What do you mean C is not equal to C++ ?
     
    Richard, May 29, 2008
    #7
  8. Kenny O'Clock

    Martin Guest

    On Wed, 28 May 2008 23:52:36 +0100, Kenny O'Clock <>
    wrote:
    > This came up in a job interview, what is the output of the program
    > below?
    > [...]
    > 1: #include <stdio.h>
    > 2: void main()
    > 3: {
    > 4: int C = 0;
    > 5: printf("C %s C++\n", C == C++ ? "==" : "!=");
    > 6: }


    I'm sure from the responses you've had you now realise that the program is
    an example of how not to write C. I would send the code back to the
    interviewers, annotated in red with the problems and explain to them why
    it is bad. Maybe (and it's a big maybe) the author *knew* what a load of
    tripe the code is and that was part of the test.

    Several years ago at interview I was shown some (production) C code and I
    pointed out that the use of memcpy for overlapping buffers was undefined..
    The interviewer was convinced that memcpy was safe to use it and that
    memmove was the unsafe one. Anyway, after the interview, I wrote them a
    letter declining a second interview and provided them an extract from the
    C Standard where it says memmove must work properly even when its operands
    overlap.

    --
    Martin
     
    Martin, May 29, 2008
    #8
  9. Richard Heathfield wrote:
    > Joachim Schmitz said:
    >
    >> Richard Heathfield wrote:

    >
    > <snip>
    >
    >>> Secondly (and I only mention it because nobody else has in the five
    >>> replies that I've seen), the program exhibits undefined behaviour in
    >>> another way, too, because the return type of main is incorrect.

    >>
    >> And win-lcc properly warns about this...

    >
    > Implementations are not obliged to diagnose incorrect signatures for
    > main. If they choose to do so, however, it would be good if they
    > could come up with some decent diagnostic text. The text given is:
    > "old-style function definition for 'main'". In fact, there's nothing
    > "old-style" about the function definition. The problem lies with the
    > return type, and void main isn't old-style - it's simply *wrong*.

    The empty parens are old style, vs. main(void).
     
    Joachim Schmitz, May 29, 2008
    #9
  10. Kenny O'Clock

    Richard Bos Guest

    "Joachim Schmitz" <> wrote:

    > Richard Heathfield wrote:
    > > Joachim Schmitz said:


    > > Implementations are not obliged to diagnose incorrect signatures for
    > > main. If they choose to do so, however, it would be good if they
    > > could come up with some decent diagnostic text. The text given is:
    > > "old-style function definition for 'main'". In fact, there's nothing
    > > "old-style" about the function definition. The problem lies with the
    > > return type, and void main isn't old-style - it's simply *wrong*.


    > The empty parens are old style, vs. main(void).


    No, they're not. void wasn't in K&R1 at all; so void main() is an _ISO_
    declaration, of a function returning nothing (which is wrong for main())
    and taking an unspecified number of arguments. If it had been an
    old-style declaration, there would have been no void on either side; it
    would have been either

    main()
    { ....

    (which, due to the default int, is correct, although bad style, for a
    main() which takes no command line arguments) or

    main()
    int argc;
    char **argv;
    { ....

    Neither of those should, of course, be used today, except when faced
    with an overwhelming necessity of porting to outdated systems.

    Richard
     
    Richard Bos, May 29, 2008
    #10
  11. On May 29, 12:04 am, "Chris Thomasson" <> wrote:

    > You should have told the interviewer that you need a valid program in order
    > to make a proper analysis. Then turn the tables and ask him if he sees
    > anything wrong with the program as-is...


    Not at all. The analysis is quite simple: "void main ()" should be
    changed to "int main ()", possibly better to "int main (void)" to make
    clear you know that the function has no arguments and that you haven't
    just forgotten about them. "C == C++" invokes undefined behavior
    because C is both modified and accessed without an intervening
    sequence point, so it is impossible to predict what will happen.
    Likely outcomes are printing "C == C++" or "C != C++", but anything
    else, including crashing, is also possible and entirely the fault of
    the programmer who wrote the code.

    Nothing wrong with this as an interview question.
     
    christian.bau, May 29, 2008
    #11
  12. On May 29, 10:44 am, Martin <> wrote:

    > Several years ago at interview I was shown some (production) C code and I
    > pointed out that the use of memcpy for overlapping buffers was undefined.
    > The interviewer was convinced that memcpy was safe to use it and that
    > memmove was the unsafe one. Anyway, after the interview, I wrote them a
    > letter declining a second interview and provided them an extract from the
    > C Standard where it says memmove must work properly even when its operands
    > overlap.


    In many implementations, memcpy (dst, dst + n, count) will behave
    exactly like memmove (dst, dst + n, count) if n > 0, while memcpy (dst
    + n, dst, count) will usually invoke some rather bizarre behaviour.
    That doesn't change the fact that it is undefined behavior, and
    relying on this is of course utterly stupid.

    For example, a highly optimised version of memcpy intended for a
    processor with vector registers could look like this:

    size_t i;

    if (size % 16 != 0)
    {
    size_t originalsize = size;
    size_t i;
    size -= size % 16;
    for (i = size; i < originalsize; ++i) dst = src ;
    }

    for (i = 0; i < size; i += 16)
    "Copy 16 bytes from src + i to dst + i";
     
    christian.bau, May 29, 2008
    #12
  13. Kenny O'Clock

    Martin Guest

    On Thu, 29 May 2008 11:47:08 +0100, christian.bau
    <> wrote:
    > Nothing wrong with this as an interview question.


    True, but I would be interested to know if the interviewer explained to
    Kenny the expected result, and used the term 'undefined behaviour' when
    doing so.

    --
    Martin
     
    Martin, May 29, 2008
    #13
  14. Kenny O'Clock

    Flash Gordon Guest

    Dan wrote, On 29/05/08 09:14:
    >> I don't even have a d:\lcc\mc71\ folder on my computer!
    >> Please help, I don't know what to do anymore!!!


    The code in question was:
    1: #include <stdio.h>
    2: void main()
    3: {
    4: int C = 0;
    5: printf("C %s C++\n", C == C++ ? "==" : "!=");
    6: }

    > I give questions like that just to seperate who is anal and who isn't (and
    > don't employ the anal ones - they are most likly to take 10 times as long to
    > write the same page code that no one is ever going to read again).


    Code never gets reviewed at your company?

    > And just incase you really are dumb, C is not equal to C++.


    The languages in question may be different, but on my system here is
    prints "C == C++".

    Amusingly, if I change it to ++C we still get:
    markg@brenda:~$ cat t.c
    #include <stdio.h>
    void main()
    {
    int C = 0;
    printf("C %s C++\n", C == ++C ? "==" : "!=");
    }
    markg@brenda:~$ gcc t.c
    t.c: In function ‘main’:
    t.c:3: warning: return type of ‘main’ is not ‘int’
    markg@brenda:~$ ./a.out
    C == C++
    markg@brenda:~$

    Personally I would not want to work for a company where code like that
    would be accepted. The "void main()" I might put up with, but the clear
    undefined behaviour for no good reason I would not. I've seen too many
    instances of C code which needlessly invokes undefined behaviour
    actually causing programs to behave incorrectly. I've fixed a lot of
    bugs by gradually increasing the compiler warning level and fixing what
    it throws up, especially the undefined behaviour.
    --
    Flash Gordon
    Now a consultant rather than a developer, so I have to stand in front of
    the customer and apologise of the bugs.
     
    Flash Gordon, May 29, 2008
    #14
  15. On Thu, 29 May 2008 12:17:21 +0000, Richard Heathfield <> wrote:

    >Joachim Schmitz said:
    >
    >> Richard Heathfield wrote:

    >
    ><snip>
    >
    >>> In fact, there's nothing
    >>> "old-style" about the function definition. The problem lies with the
    >>> return type, and void main isn't old-style - it's simply *wrong*.

    >> The empty parens are old style, vs. main(void).

    >
    >If that's truly what the message means, it's silly - the compiler is
    >ignoring a genuine error and instead flagging up perfectly harmless code.


    You are ignoring third warning. If I add prototype for main like below,
    compiler only issues one warning

    #include <stdio.h>
    void main(int argc, char **argv)
    {
    int C = 0;
    printf("C %s C++\n", C == C++ ? "==" : "!=");
    }

    $ make foo9.exe
    lc -ansic -pedantic -A -shadows -unused -O -c foo9.c -o foo9.obj
    Warning foo9.c: 3 '
    Error foo9.c: 3 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
    Error c:\tmp\clc\foo9.c 3 Compiler error (trap). Stopping compilation
    1 error
    make: *** [foo9.obj] Error 1

    Perhaps there is bug.
     
    Three Headed Monkey, May 29, 2008
    #15
  16. Kenny O'Clock

    user923005 Guest

    On May 29, 3:18 pm, Three Headed Monkey <>
    wrote:
    > On Thu, 29 May 2008 12:17:21 +0000, Richard Heathfield <> wrote:
    > >Joachim Schmitz said:

    >
    > >> Richard Heathfield wrote:

    >
    > ><snip>

    >
    > >>> In fact, there's nothing
    > >>> "old-style" about the function definition. The problem lies with the
    > >>> return type, and void main isn't old-style - it's simply *wrong*.
    > >> The empty parens are old style, vs. main(void).

    >
    > >If that's truly what the message means, it's silly - the compiler is
    > >ignoring a genuine error and instead flagging up perfectly harmless code.

    >
    > You are ignoring third warning. If I add prototype for main like below,
    > compiler only issues one warning
    >
    >   #include <stdio.h>
    >   void main(int argc, char **argv)
    >   {
    >     int C = 0;
    >     printf("C %s C++\n", C == C++ ? "==" : "!=");
    >   }
    >
    > $ make foo9.exe
    > lc -ansic -pedantic -A -shadows -unused -O -c foo9.c -o foo9.obj
    > Warning foo9.c: 3  '
    > Error foo9.c: 3  compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
    > Error c:\tmp\clc\foo9.c 3 Compiler error (trap). Stopping compilation
    > 1 error
    > make: *** [foo9.obj] Error 1
    >
    > Perhaps there is bug.


    Refusing to compile code that exhibits undefined behavior seems more
    like a feature than a bug to me.
    In fact, I wish that all my compilers would do that. (At least in the
    cases where undefined behavior can be repaired).
     
    user923005, May 29, 2008
    #16
  17. On Fri, 30 May 2008, Three Headed Monkey wrote:

    >On Thu, 29 May 2008 12:17:21 +0000, Richard Heathfield <> wrote:
    >
    >>Joachim Schmitz said:
    >>
    >>> Richard Heathfield wrote:

    >>
    >><snip>
    >>
    >>>> In fact, there's nothing
    >>>> "old-style" about the function definition. The problem lies with the
    >>>> return type, and void main isn't old-style - it's simply *wrong*.
    >>> The empty parens are old style, vs. main(void).

    >>
    >>If that's truly what the message means, it's silly - the compiler is
    >>ignoring a genuine error and instead flagging up perfectly harmless code.

    >
    >You are ignoring third warning. If I add prototype for main like below,
    >compiler only issues one warning
    >
    > #include <stdio.h>
    > void main(int argc, char **argv)
    > {
    > int C = 0;
    > printf("C %s C++\n", C == C++ ? "==" : "!=");
    > }
    >
    >$ make foo9.exe
    >lc -ansic -pedantic -A -shadows -unused -O -c foo9.c -o foo9.obj
    >Warning foo9.c: 3 '
    >Error foo9.c: 3 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
    >Error c:\tmp\clc\foo9.c 3 Compiler error (trap). Stopping compilation
    >1 error
    >make: *** [foo9.obj] Error 1
    >
    >Perhaps there is bug.


    I may be misremembering but I think this is a limitation in the
    free version and you need to buy a premium commercial license to
    be able to use 'void main()' in lcc-win.
     
    Sandpaper Supplier for Pinocchio, May 30, 2008
    #17
  18. Eric Sosman <> writes:
    > user923005 wrote:
    >> Refusing to compile code that exhibits undefined behavior seems more
    >> like a feature than a bug to me.
    >> In fact, I wish that all my compilers would do that. (At least in the
    >> cases where undefined behavior can be repaired).

    >
    > IMHO that's an unfortunate wish. Here, for example,
    > is the start of a program that exhibits undefined behavior:
    >
    > #include <unistd.h>
    > ...
    >
    > Do you really want the compiler to reject it?
    >
    > As the Rationale puts it, "the ability to write machine-
    > specific code is one of the strengths of C." If C were
    > *unable* to poke I/O registers, *unable* to call dlsym() and
    > convert a void* to a function pointer, *unable* to overflow
    > an `int' without trapping, C would be far less useful than
    > it actually is.


    Sure, but there's undefined behavior and then there's undefined
    behavior.

    There are plenty of constructs whose behavior the standard doesn't
    define that can nevertheless be useful in non-portable code.

    On the other hand, some constructs, such as ``C == C++'' or
    ``i = i++'' are, in a sense, more purely undefined, to the extent that
    they should never appear in normal C code. Regardless of the
    portability of the program, there's always a better way to expression
    whatever the intent was.

    For such constructs, I certainly have no problem with a compiler
    warning about them, or even rejecting the translation unit *if* it can
    prove that the code will always be executed.

    The tricky (and perhaps undecidable) part is determining which
    instances of UB are potentially ok and which are not.

    (On the other hand, the way in which the particular compiler
    terminated, with an internal assertion failure, indicates a bug in
    that compiler -- though the standard doesn't say what a diagnostic has
    to look like.)

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 30, 2008
    #18
  19. Richard Heathfield <> writes:
    > Three Headed Monkey said:

    [...]
    >> Error foo9.c: 3 compiler error in d:\lcc\mc71\types.c--assertion failure
    >> at line 868 Error c:\tmp\clc\foo9.c 3 Compiler error (trap). Stopping
    >> compilation 1 error
    >> make: *** [foo9.obj] Error 1
    >>
    >> Perhaps there is bug.

    >
    > Perhaps there is, but you haven't shown this. The cited program
    > exhibits undefined behaviour, so the implementation is allowed to do
    > anything it likes with it - and since I don't see any syntax errors
    > or constraint violations, I see no requirement for any message
    > whatsoever. For the compiler to have a bug that is relevant to the
    > above code, it would surely have to be exhibiting (or harbouring)
    > some inappropriate behaviour when given that code. But since the
    > Standard allows all behaviours for such code, it is hard to see how
    > it could be used to demonstrate a bug in the implementation.


    I think you're using a far too narrow definition of "bug".

    The way I use the term, a failure to conform to the standard (on the
    part of an implementation that claims to conform to the standard) is
    certainly a bug, but many other things are bugs as well. Responding
    to undefined behavior by blowing up rather than by printing a proper
    error message, though it doesn't violate the standard, is, in my
    opinion, a bug.

    Also, I suspect (though I have no direct evidence of this) that the
    compiler would react the same way to the same code in a function
    that's never called. In such a case, the standard doesn't permit the
    compiler to reject the translation unit.

    (BTW, I'm not trying to pick on lcc-win here.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 30, 2008
    #19
  20. Kenny O'Clock

    user923005 Guest

    On May 29, 6:29 pm, Eric Sosman <> wrote:
    > user923005 wrote:
    >
    > > Refusing to compile code that exhibits undefined behavior seems more
    > > like a feature than a bug to me.
    > > In fact, I wish that all my compilers would do that. (At least in the
    > > cases where undefined behavior can be repaired).

    >
    >      IMHO that's an unfortunate wish.  Here, for example,
    > is the start of a program that exhibits undefined behavior:
    >
    >         #include <unistd.h>
    >         ...
    >
    > Do you really want the compiler to reject it?


    Can the compiler do anything about it?

    In the case of:

    i = i++;

    It can.

    In the second case, it can't.

    >      As the Rationale puts it, "the ability to write machine-
    > specific code is one of the strengths of C."  If C were
    > *unable* to poke I/O registers, *unable* to call dlsym() and
    > convert a void* to a function pointer, *unable* to overflow
    > an `int' without trapping, C would be far less useful than
    > it actually is.
    >
    >      There is an unfortunate tendency among novice C programmers
    > to resort to undefined or implementation-defined behavior when
    > portable alternatives exist if one is informed enough and
    > careful enough to use them.  But sometimes C is used to achieve
    > effects that simply aren't portable, that rely on behavior left
    > undefined by the C Standard but defined by the platforms of
    > interest.  Such programs do compile, and should compile, even
    > though the C Standard does not define their behavior.


    I agree that:
    1. It is far better to use fully portable code if possible.
    2. Almost every real project invokes undefined behavior at some point
    3. Most of the time, we do not even recognize that the behavior is
    undefined
    4. Even when we recognize that the behavior is undefined, we probably
    can't do anything about it (e.g. unistd.h or windows.h)

    There are also rare cases where we know for sure that:
    1. The behavior is undefined
    2. The undefined behavior is undesirable

    such as:
    i = i++; /* There is literally no sensible reason imaginable to do
    this. */

    In these few cases, I think a very sensible solution is to issue an
    error message and refuse to create a binary.
     
    user923005, May 30, 2008
    #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. John Bentley

    Output / Debug window output bug?

    John Bentley, Sep 10, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    609
    John Bentley
    Sep 10, 2003
  2. chuck amadi
    Replies:
    1
    Views:
    509
    Larry Bates
    Jun 23, 2004
  3. Puneet
    Replies:
    16
    Views:
    1,159
    Daniel Vallstrom
    Mar 20, 2005
  4. Paul
    Replies:
    1
    Views:
    446
  5. jmr
    Replies:
    2
    Views:
    349
Loading...

Share This Page