Unexpected behaviour

Discussion in 'C++' started by Roal Zanazzi, Sep 12, 2006.

  1. Roal Zanazzi

    Roal Zanazzi Guest

    Hi everyone,

    I've accidentally found something in my C++ code that is definitively weird.
    It is obviously an error in my code, but it is not signalled by
    Microsoft Visual C++ 2005 compiler, not even with a warning.
    While Borland TurboC++ 2006 compiler stop at it as an error
    (E2034 Cannot convert 'bool' to 'int *').


    // Code start here //
    #include <iostream>

    void func(int* p1, bool p2 = false)
    {
    std::cout << p1 << ", " << p2 << std::endl;
    }

    int main(int argc, char* argv[])
    {
    func(false); // <<< PROBLEM!
    return 0;
    }
    // Code end here //


    What I was doing is trying to pass the second parameter explicitely
    (even though it has the same value as the default one),
    forgetting the first parameter (think about someone else changed the
    function signature without telling you).

    I'm curious about what the standard says about this situation.
    Do the standard mandate an implicit cast from false to 0 (zero)?
    Should the compiler issue an error, at least a warning or let it go?

    If I replace the "offending line" with:
    func(true); // <<< PROBLEM!
    in this case also the Microsoft compiler issues an error
    (C2664: 'func' : cannot convert parameter 1 from 'bool' to 'int *'),
    the same one given by Borland compiler.

    TIA
    --
    Roal Zanazzi
     
    Roal Zanazzi, Sep 12, 2006
    #1
    1. Advertising

  2. Roal Zanazzi

    David Harmon Guest

    On Tue, 12 Sep 2006 13:04:20 +0200 in comp.lang.c++, Roal Zanazzi
    <> wrote,
    >If I replace the "offending line" with:
    > func(true); // <<< PROBLEM!


    The definition of a null pointer is "An integral constant
    expression rvalue of integer type that evaluates to zero".
    bool is an integer type. false evaluates to zero. true does not.
     
    David Harmon, Sep 12, 2006
    #2
    1. Advertising

  3. Roal Zanazzi

    Roal Zanazzi Guest

    David Harmon ha scritto:
    > On Tue, 12 Sep 2006 13:04:20 +0200 in comp.lang.c++, Roal Zanazzi
    > <> wrote,
    >> If I replace the "offending line" with:
    >> func(true); // <<< PROBLEM!

    >
    > The definition of a null pointer is "An integral constant
    > expression rvalue of integer type that evaluates to zero".
    > bool is an integer type. false evaluates to zero. true does not.
    >

    This makes sense, somewhat.
    Like saying that apples and oranges are different until you have none of
    both :p

    So false could be used instead of 0 (zero) or NULL... mmmh...

    Anyway I see this as a potential cause of problems, what if I write:

    // code start here //
    #include <iostream>

    void func(int* p1, bool p2 = true)
    {
    std::cout << p1 << ", " << p2 << std::endl;
    }

    int main(int argc, char* argv[])
    {
    func(false); // <<< not really passing p2!!!
    return 0;
    }
    // code end here //

    ....and I think I'm passing a p2 param value different from the default
    one, because I'm not aware of the presence of p1 param?
    In this case I get no warning, BUT the program will not perform as expected.
    This seems a lack of information, I would expect a warning here, or am I
    completely wrong?

    N.B. I'm not stating that the C++ standard is wrong (I'm not even near
    to that level of knowledge), but that the compiler (Visual C++ 2005)
    leaves a hole for potential bugs.
    Borland C++ 2006 compiler seems to be non-compliant giving error.
    g++ (GCC) 4.1.1 20060525 (Red Hat 4.1.1-1) gives no warning.

    I'm curious, what are the results with other compilers (sorry, I have
    only those 3)?

    --
    Roal Zanazzi
     
    Roal Zanazzi, Sep 12, 2006
    #3
  4. Roal Zanazzi wrote:
    > Hi everyone,
    >
    > I've accidentally found something in my C++ code that is definitively
    > weird.
    > It is obviously an error in my code, but it is not signalled by


    Obvious to me and you, but not to the compiler; the compiler is required
    to accept what you've written below.

    > Microsoft Visual C++ 2005 compiler, not even with a warning.
    > While Borland TurboC++ 2006 compiler stop at it as an error
    > (E2034 Cannot convert 'bool' to 'int *').


    TurboC++ is wrong in this case.

    > // Code start here //
    > #include <iostream>
    >
    > void func(int* p1, bool p2 = false)
    > {
    > std::cout << p1 << ", " << p2 << std::endl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > func(false); // <<< PROBLEM!


    false is a valid Null Pointer Constant; It is a constant integer
    expression that evaluates to zero. This function call is no different
    than any of the following:

    func(0);
    func(0U);
    func(0L);
    func(0UL);
    func('\0');
    func(1-1);
    func(25 / 100);
    func(sizeof(char) / 2);

    or any of the other infinite variations on the same theme.

    > If I replace the "offending line" with:
    > func(true); // <<< PROBLEM!


    (true) on the other hand is not a valid Null Pointer Constant (it does
    not evaluate to zero).


    --
    Clark S. Cox III
     
    Clark S. Cox III, Sep 12, 2006
    #4
  5. Roal Zanazzi

    Guest

    Clark S. Cox III wrote:
    > Roal Zanazzi wrote:
    > > Hi everyone,
    > >
    > > I've accidentally found something in my C++ code that is definitively
    > > weird.
    > > It is obviously an error in my code, but it is not signalled by

    >
    > Obvious to me and you, but not to the compiler; the compiler is required
    > to accept what you've written below.


    It must accept the code, but it may still give you a warning. Using
    false
    as a NPC is probably more often a mistake than intentional. The tricky
    bit
    for compiler writers is recognizing the ((int*) false) cases where you
    try to
    make the intent explicit.

    Regards,
    Michiel Salters.
     
    , Sep 12, 2006
    #5
  6. Roal Zanazzi

    Howard Guest

    "Roal Zanazzi" <> wrote in message
    news:cXyNg.18327$...
    > David Harmon ha scritto:
    >> On Tue, 12 Sep 2006 13:04:20 +0200 in comp.lang.c++, Roal Zanazzi
    >> <> wrote,
    >>> If I replace the "offending line" with:
    >>> func(true); // <<< PROBLEM!

    >>
    >> The definition of a null pointer is "An integral constant
    >> expression rvalue of integer type that evaluates to zero".
    >> bool is an integer type. false evaluates to zero. true does not.
    >>

    > This makes sense, somewhat.
    > Like saying that apples and oranges are different until you have none of
    > both :p
    >
    > So false could be used instead of 0 (zero) or NULL... mmmh...
    >
    > Anyway I see this as a potential cause of problems, what if I write:
    >
    > // code start here //
    > #include <iostream>
    >
    > void func(int* p1, bool p2 = true)
    > {
    > std::cout << p1 << ", " << p2 << std::endl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > func(false); // <<< not really passing p2!!!
    > return 0;
    > }
    > // code end here //
    >
    > ...and I think I'm passing a p2 param value different from the default
    > one, because I'm not aware of the presence of p1 param?


    You can't leave off the first parameter, but include the second, ever. You
    could leave off the second one, since it's got a default value, but not the
    other way around.

    And it's perfectly legal to pass a constant integer value as a pointer.
    (That's why NULL is valid, after all.) There's no way the compiler could
    "guess" that, simply because false is usually used as a boolean, you must
    have somehow forgotten the first parameter, and meant that to be the second
    one. (Can you imagine trying to write the code to decide that that was the
    case?)


    I don't see how this could ever be a real problem, though. How could you
    not be aware of the existence of a first parameter, but at the same time
    know the proper type of the second parameter?

    -Howard
     
    Howard, Sep 12, 2006
    #6
  7. Roal Zanazzi

    Puppet_Sock Guest

    Roal Zanazzi wrote:
    [snips]
    > // Code start here //
    > #include <iostream>
    >
    > void func(int* p1, bool p2 = false)
    > {
    > std::cout << p1 << ", " << p2 << std::endl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > func(false); // <<< PROBLEM!
    > return 0;
    > }
    > // Code end here //


    This looks like a job for a lint type program. There are a few.
    Have a google around.

    A "nice" compiler would certainly hold your hand over such
    and issue. Maybe issue a warning along the lines of "suspicious
    conversion" or something.
    Socks
     
    Puppet_Sock, Sep 12, 2006
    #7
  8. Roal Zanazzi

    Roal Zanazzi Guest

    Howard ha scritto:
    > "Roal Zanazzi" <> wrote in message
    > news:cXyNg.18327$...
    >> David Harmon ha scritto:
    >>> On Tue, 12 Sep 2006 13:04:20 +0200 in comp.lang.c++, Roal Zanazzi
    >>> <> wrote,
    >>>> If I replace the "offending line" with:
    >>>> func(true); // <<< PROBLEM!
    >>> The definition of a null pointer is "An integral constant
    >>> expression rvalue of integer type that evaluates to zero".
    >>> bool is an integer type. false evaluates to zero. true does not.
    >>>

    >> This makes sense, somewhat.
    >> Like saying that apples and oranges are different until you have none of
    >> both :p
    >>
    >> So false could be used instead of 0 (zero) or NULL... mmmh...
    >>
    >> Anyway I see this as a potential cause of problems, what if I write:
    >>
    >> // code start here //
    >> #include <iostream>
    >>
    >> void func(int* p1, bool p2 = true)
    >> {
    >> std::cout << p1 << ", " << p2 << std::endl;
    >> }
    >>
    >> int main(int argc, char* argv[])
    >> {
    >> func(false); // <<< not really passing p2!!!
    >> return 0;
    >> }
    >> // code end here //
    >>
    >> ...and I think I'm passing a p2 param value different from the default
    >> one, because I'm not aware of the presence of p1 param?

    >
    > You can't leave off the first parameter, but include the second, ever. You
    > could leave off the second one, since it's got a default value, but not the
    > other way around.
    >

    Sorry Howard, but it is exactly what I've done in the code above:
    I presumed that the function func() was just taking 1 parameter of type
    bool, with default value of true (and I've passed false to _change the
    function behaviour_). I presumed this because the function signature was
    like that, in the past.
    Think about this in a more complex scenario where the function func()
    comes from a library developed by someone else, and this person changes
    the function signature adding 1 parameter (a pointer).
    A "standard compliant" compiler will continue to compile without even
    giving a small warning, and (in the worst-but-not-rare case) your
    application will eventually blow up (at test time if you have been
    smart, in your customer's eye if not).

    > And it's perfectly legal to pass a constant integer value as a pointer.
    > (That's why NULL is valid, after all.) There's no way the compiler could
    > "guess" that, simply because false is usually used as a boolean, you must
    > have somehow forgotten the first parameter, and meant that to be the second
    > one. (Can you imagine trying to write the code to decide that that was the
    > case?)
    >

    Any compiler CAN (and should, IMHO) issue a warning in this case, giving
    the developer at least a minimal alarm about something that could be an
    unwanted mistake.
    Just like an assignment in a if() condition...

    > I don't see how this could ever be a real problem, though. How could you
    > not be aware of the existence of a first parameter, but at the same time
    > know the proper type of the second parameter?
    >

    Sh*t happens...
    See above.

    Maybe I'm just going pedantic, but I've yet to read a good reason for
    this lack of warning.

    --
    Roal Zanazzi
     
    Roal Zanazzi, Sep 12, 2006
    #8
  9. Roal Zanazzi

    Howard Guest

    "Roal Zanazzi" <> wrote in message
    news:nlANg.18533$...
    > Howard ha scritto:


    >> And it's perfectly legal to pass a constant integer value as a pointer.
    >> (That's why NULL is valid, after all.) There's no way the compiler could
    >> "guess" that, simply because false is usually used as a boolean, you must
    >> have somehow forgotten the first parameter, and meant that to be the
    >> second one. (Can you imagine trying to write the code to decide that
    >> that was the case?)
    >>

    > Any compiler CAN (and should, IMHO) issue a warning in this case, giving
    > the developer at least a minimal alarm about something that could be an
    > unwanted mistake.
    > Just like an assignment in a if() condition...


    Well, a warning could be issued for the use of the constant false where a
    pointer is expected. That would be easy, and maybe even useful. (You might
    want to discuss this on comp.std.c++.)

    But what I was saying was that it wasn't practical for the compiler to
    somehow know you were passing the second parameter, and accidently leaving
    out the first.

    Imagine if, instead of having an int* and a bool parameter, you had two bool
    parameters, and then made the same mistake as you did, passing false for the
    second one, not knowing that a new bool parameter had been added before it.
    Now, would you still expect a warning? Obviously not, since false is a
    valid bool value for the first parameter, and leaving off the second
    parameter is allowed because of the default value.

    That's what I was really getting at.

    But, the situation you described should never have occured, really. Someone
    modified a function and didn't make absolutely sure that everyone who might
    call that function knew that a change had been made.

    Which is why a good practice (at least in my opinion) is to NEVER change a
    function's signature. Instead, add new functions which do the work you now
    need done, and deprecate the old function. (One way to do that is to throw
    an exception if the old function is called. There are other ways, as well.
    But most importantly, whatever you do, document the change!) This is how
    things are done in the COM/DCOM world. An interface is allowed to grow by
    adding new functions, but changes are not allowed to existing function
    signatures.

    -Howard
     
    Howard, Sep 12, 2006
    #9
  10. Roal Zanazzi

    Roal Zanazzi Guest

    Howard wrote
    > "Roal Zanazzi" <> wrote in message
    > news:nlANg.18533$...
    >> Any compiler CAN (and should, IMHO) issue a warning in this case, giving
    >> the developer at least a minimal alarm about something that could be an
    >> unwanted mistake.
    >> Just like an assignment in a if() condition...

    >
    > Well, a warning could be issued for the use of the constant false where a
    > pointer is expected. That would be easy, and maybe even useful. (You might
    > want to discuss this on comp.std.c++.)
    >

    Maybe I'm not the right person, my lack of deep knowledge in the
    standard is not a good background for such an highly technical group...

    > But what I was saying was that it wasn't practical for the compiler to
    > somehow know you were passing the second parameter, and accidently leaving
    > out the first.
    >

    Ok, I get your point, anyway mine was not that the compiler should wear
    the fortune-teller hat and read my mind ;-) It surely (hopefully) cannot
    do it.

    > Imagine if, instead of having an int* and a bool parameter, you had two bool
    > parameters, and then made the same mistake as you did, passing false for the
    > second one, not knowing that a new bool parameter had been added before it.
    > Now, would you still expect a warning? Obviously not, since false is a
    > valid bool value for the first parameter, and leaving off the second
    > parameter is allowed because of the default value.
    >
    > That's what I was really getting at.
    >

    Understood and perfectly logic. I obviously agree with you.
    But I see my point as different, because it applies to a different and
    well defined case: the compiler (can and) should issue a warning
    whenever it finds a _bool to pointer implicit conversion_.
    Correct me if I'm wrong here, but I think that this situation could be
    helpful most of the times (if not all) to prevent potentially weird bugs.


    > But, the situation you described should never have occured, really. Someone
    > modified a function and didn't make absolutely sure that everyone who might
    > call that function knew that a change had been made.
    >

    Believe me, I'm not the one that knows nothing about SE at al. :p

    > Which is why a good practice (at least in my opinion) is to NEVER change a
    > function's signature. Instead, add new functions which do the work you now
    > need done, and deprecate the old function.
    >

    I tend to stay away from NEVER and ALWAYS.
    By I agree with you about it being a _good practice_.

    > (One way to do that is to throw
    > an exception if the old function is called. There are other ways, as well.
    > But most importantly, whatever you do, document the change!) This is how
    > things are done in the COM/DCOM world. An interface is allowed to grow by
    > adding new functions, but changes are not allowed to existing function
    > signatures.
    >

    I know, I know... we have some ActiveX control (sorry about the OT)
    which are growing full of *Ex() functions that add some parameter over
    the *() original functions...
    In this case the function I'm calling has no public visibility (just
    used inside a DLL library).

    --
    Roal Zanazzi
     
    Roal Zanazzi, Sep 13, 2006
    #10
    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. Mark
    Replies:
    4
    Views:
    2,961
    scoude
    Jan 12, 2011
  2. Steven Van den Berghe

    unexpected map behaviour

    Steven Van den Berghe, Aug 28, 2003, in forum: C++
    Replies:
    2
    Views:
    427
    Christian Jan├čen
    Aug 28, 2003
  3. Old Wolf
    Replies:
    1
    Views:
    395
    Victor Bazarov
    Feb 4, 2004
  4. Ioannis Vranos

    Unexpected behaviour

    Ioannis Vranos, Sep 23, 2004, in forum: C++
    Replies:
    36
    Views:
    912
    Rolf Magnus
    Sep 24, 2004
  5. Richard Philips

    Unexpected python behaviour

    Richard Philips, Nov 28, 2003, in forum: Python
    Replies:
    2
    Views:
    320
    Jay O'Connor
    Nov 28, 2003
Loading...

Share This Page