Question

I have very basic code to read raw data from array and interpret it as data of different type. The assertion in the code fails, from what it looks like incorrect recasting within ternary operator in C. This is platform specific, compiled for embedded processor (Analog Devices Tiger Sharc 201). Any idea what may be happening here? I'm at the point of contacting Analog Devices, but figured there is always a chance someone extremely smart can figure out what may be wrong.

#include <assert.h>

typedef union {
    unsigned int uint32;
    float float32;
} c_t;

int main( int argc, char *argv[] )
{   
    unsigned int r;

    int data_type;

    //data is a raw array, could be floats or unsigned int
    unsigned int data[] = {470698344};    

    //cast raw data as mixed union type
    c_t mixed = *(c_t*) data;       

    //interpret all data as unsigned integer
    data_type = 1;

    //this is where cast to float takes place, resulting in loss of precision
    r = data_type ? mixed.uint32 : mixed.float32;

    //also fails, with no union, results in same code
    //r = data_type ? *((unsigned int *)data) : *((float *) data);

    //r = 470698336, loss of precision 
    //due to incorrect cast inside ternary conditional statement at line 23?
    assert(r == 470698344);             

    return 0;
}
Was it helpful?

Solution

The type of the conditional expression x ? a : b is the common type of the types of the expressions a and b. The common type of uint32_t and float is... float. Whichever of the two operands is evaluated, its value is converted to the common type, and that's the value of the conditional expression.

Your number 470698344 is 29 bits long, but your float can only 24 bits of precision. So in the conversion, precision is lost. When the value of the conditional expression is assigned to r, this less-precise floating point value is truncated to an integer, which is different from 470698344.

OTHER TIPS

Found a good reference on this here

  • If both expressions are of the same type, the result is of that type.
  • If both expressions are of arithmetic or enumeration types, the usual arithmetic conversions (covered in Arithmetic Conversions) are performed to convert them to a common type.
  • If both expressions are of pointer types or if one is a pointer type and the other is a constant expression that evaluates to 0, pointer conversions are performed to convert them to a common type.
  • If both expressions are of reference types, reference conversions are performed to convert them to a common type.
  • If both expressions are of type void, the common type is type void.
  • If both expressions are of a given class type, the common type is that class type.

Any combinations of second and third operands not in the preceding list are illegal. The type of the result is the common type, and it is an l-value if both the second and third operands are of the same type and both are l-values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top