Thread: bug in ternary operator ?:

  1. #1
    Registered User
    Join Date
    Feb 2011
    Posts
    7

    bug in ternary operator ?:

    Given the following code snippet:

    Code:
        unsigned long long x;
    
        x = (0 ? (double) 0 : 0xf1debc9a78563412ULL);
    On GCC 4.5.0 on a i686 mingw32_NT-5.1 I get the result 0xf1debc9a78563800. It appears the constant value is being converted to a double then back to an unsigned long long. Is this a feature or a bug? If you ask why this is useful I was trying to use it as part of size independent byte swap macro:

    Code:
    #define _floating_type(type) (((type) 0.25) && ((type) 0.25 - 1))
    
    #define BSWAP(x, type)                                                                \
        (_floating_type (type) && (sizeof (type) == sizeof  (float)) ? bswap_float  (x) : \
        (_floating_type (type) && (sizeof (type) == sizeof (double)) ? bswap_double (x) : \
        (sizeof (type) == sizeof (uint8_t)  ? (x)         :                               \
        (sizeof (type) == sizeof (uint16_t) ? bswap16 (x) :                               \
        (sizeof (type) == sizeof (uint32_t) ? bswap32 (x) :                               \
        (sizeof (type) == sizeof (uint64_t) ? bswap64 (x) : (1/0))))))))

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by wiglaf View Post
    Given the following code snippet:

    Code:
        unsigned long long x;
    
        x = (0 ? (double) 0 : 0xf1debc9a78563412ULL);
    Mostly it's failing because you are trying to assign a double to an int and you can't do that.
    Plus your bracketing is wrong.

  3. #3
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    It's not a feature or a bug, it's a defined operation.

    x = (0 ? (double) 0 : 0xf1debc9a78563412ULL);

    This is the same as:

    x = 0xf1debc9a78563412ULL;

    because the condition is false.
    Last edited by whiteflags; 03-31-2011 at 02:56 PM. Reason: improved color

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Even if we assume your parenthesis are fine, why even have ? : in your test case?
    Code:
    if( 0 )
        x = 0;
    else
        x = number;
    See what you are doing there? if( 0 ) will never be true.

    edit - man I'm slow today

    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Registered User
    Join Date
    Feb 2011
    Posts
    7
    PLEASE!! I did not ask why the code is wrong. I am asking why the compiler does not interpret it as I would expect. Both conditions of the ?: operator have different types, but although the first condition is not taken the result of the second condition is cast to the type of the first. I would not expect this behavior. Is the behavior given in a standard or is this a compiler bug?
    I appreciate your time.

  6. #6
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Most compilers assume the value of part B and C of the A?B:C is the same data type.
    IIRC, Borland C++ (version 5.5) does not like it if they are not the same and errs out.
    It looks like the compiler you are using, promotes one of them to match the other.

    Tim S.
    Last edited by stahta01; 03-31-2011 at 03:28 PM.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    >> PLEASE!! I did not ask why the code is wrong.

    I know.

    >> I am asking why the compiler does not interpret it as I would expect.

    And I'm telling you, man, why it's not.

    quzah puts it plainly. The ternary operator is just another way to write if-else, except that you're limited to executing a single expression for either branch.

    >> Both conditions of the ?: operator have different types, but although the first condition is not taken the result of the second condition is cast to the type of the first.

    Types are irrelevant. The condition of the ternary operator is false, and will always be false, so the expression "(double) 0" is never executed. What gets assigned to x in the other branch may incidentally mean the same thing as that, but it doesn't matter. It's how ternary is defined to work by the standard that matters.

    >> I would not expect this behavior. Is the behavior given in a standard or is this a compiler bug?

    Again, not a feature or a bug.

    >> I appreciate your time.

    Yes, you're welcome, please be more respectful in the future. "PLEASE I didn't ask what is wrong" ... yes you did, and people gave you the answer to your actual question.

  8. #8
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Both conditions of the ?: operator have different types, but although the first condition is not taken the result of the second condition is cast to the type of the first. I would not expect this behavior. Is the behavior given in a standard or is this a compiler bug?
    The former. While the second and third operands have different types, the conditional operator determines a common type and one or both are converted to that type. How is this determined, you ask? A fine question. Answer: by applying the usual arithmetic conversions to both operands (assuming both have arithmetic type, which they do in this example).

    What are the usual arithmetic conversions (you may be asking yourself)? They're a set of rules, the start of which I shall quote here:
    Quote Originally Posted by C99 6.3.1.8
    First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose corresponding real type is long double.

    Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.
    Since one is a double, the other (your unsigned long long) is converted to double, then back to unsigned long long by assignment. Thus you should get the same value as you would doing:
    Code:
    printf("%llx\n", (unsigned long long)(double)0xf1debc9a78563412ULL);

  9. #9
    Registered User
    Join Date
    Feb 2011
    Posts
    7
    I just tried the following and also received the same result:

    Code:
        x = (1 ? 0xF1DEBC9A78563412ULL : (double) 0.0);
    So it does appear the compiler is just promoting both types to double.

    To be clear I am not asking how to use the ?: operator, I'm asking why my compiler does this:

    Code:
    if (0) {
        x = (double) 0.0;
    } else {
        x = (double) 0xF1DEBC9A78563412ULL;
    }
    When I expect it to do this

    Code:
    if (0) {
        x = (double) 0.0;
    } else {
        x = 0xF1DEBC9A78563412ULL;
    }
    The snippet of code was simply the smallest example that showed this.

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    In the following assignment statement:

    Code:
    x = (0 ? (double) 0 : 0xf1debc9a78563412ULL);
    The thing on the right hand side, in parentheses, is an expression. All expressions have a well-defined type. An expression may not have two types at the same time. Thus, the type of the expression on the right must be either double or unsigned long long. The compiler chooses by following the same rules it would follow if you tried to use a binary operator on a double and an unsigned long long -- the result is a DOUBLE.

    Thus, the value 0xf1debc9a78563412ULL is converted to a double, because the type of the RHS is double. It is being assigned to an unsigned long long. Thus, it is converted to that type. The result is not the same because it took a round-trip through floating-point land.

    The type of variable on the LHS of the assignment statement is absolutely irrelevant to this. There is nothing mysterious happening. You seem to believe that an expression can somehow, through some quantum-mechanical mechanism, have two types simultaneously. That is NOT possible.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  11. #11
    Registered User
    Join Date
    Feb 2011
    Posts
    7
    brewbuck, the right hand side is a conditional expression. It evaluates to one expression or the other. There is nothing quantum mechanical about that. It is either one or the other. So I didn't see any reason why the return type can't be the same as the evaluated expression. After all that would make the ternary operator ?: equivalent to an if/else statement. That is, the following two expressions would be the same:

    Code:
    double b;
    long long int c, x;
    
    x = a ? b : c;
    
    if (a) {
      x = b;
    } else {
      x = c;
    }
    But it is not. The else statement is evaluated as x = (long long int) (double) c in the ternary operator. This can make for some obscure bugs. I did find this behavior documented elsewhere, so I'll work around it...

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by wiglaf
    So I didn't see any reason why the return type can't be the same as the evaluated expression.
    If so, the type of the expression would be determined at run time, not compile time.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by wiglaf View Post
    After all that would make the ternary operator ?: equivalent to an if/else statement.
    The ternary operator is not equivalent to an if/else. It is similar. There's a big difference.


    Quzah.
    Hope is the first step on the road to disappointment.

  14. #14
    Registered User
    Join Date
    Feb 2011
    Posts
    7
    Thanks laserlight, that is what I was looking for...

  15. #15
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by wiglaf View Post
    But it is not. The else statement is evaluated as x = (long long int) (double) c in the ternary operator. This can make for some obscure bugs. I did find this behavior documented elsewhere, so I'll work around it...
    Having other sorts of wrong conceptions can also make for obscure bugs. In general, being wrong leads to a variety of problems.

    EDIT: I didn't intend that to be as snarky as it sounded, sorry.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. why can't my perceptron learn correctly?
    By yann in forum C Programming
    Replies: 25
    Last Post: 10-15-2010, 12:26 AM
  2. Smart pointer class
    By Elysia in forum C++ Programming
    Replies: 63
    Last Post: 11-03-2007, 07:05 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. Operator Overloading (Bug, or error in code?)
    By QuietWhistler in forum C++ Programming
    Replies: 2
    Last Post: 01-25-2006, 08:38 AM
  5. operator overloading and dynamic memory program
    By jlmac2001 in forum C++ Programming
    Replies: 3
    Last Post: 04-06-2003, 11:51 PM