Continuation of discussion on float vs double with printf.

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I split off this discussion from the other thread as it really wasn't related to the original topic.

So I understand how floats are promoted to doubles on variadic functions like printf() but what I still don't understand is why the compiler barfs when percent f is used and a float is passed down.

If it is being promoted to double, then why should the compiler barf on the float argument as the printf() function will in fact be receiving a double?

It doesn't do this with gcc on the PC and on the PC floats and doubles are not even the same size.

(I'll admit my gcc command options are not the same for the two environments)

So I come back to my original question of why should you have to cast a float to a double when using printf() and percent f with avr-gcc but not with the PC version of gcc?

Why can't the avr-gcc compiler be smart enough to know that the float will be promoted to a double and everything is ok instead of requiring an explicit cast?

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't really understand it either. On the PC, if I use the format % Lf
(long double), it gives me the (correct) warning:

foo.c:8: warning: format '% Lf' expects type 'long double', but argument 2 has type 'double'

Compiling the same code with avr-gcc gives:

foo.c:8: warning: format '% Lf' expects type 'long double', but argument 2 has type 'float'

Maybe this is an artifact of the AVR-GCC implementation where sizeof(double) = sizeof(float).

Anyway, it's probably good practise to make the type conversion obvious by adding
a typecast to double. Implied type conversions can be dangerous to the innocent
reader of the code.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
I don't really understand it either. On the PC, if I use the format % Lf
(long double), it gives me the (correct) warning:

foo.c:8: warning: format '% Lf' expects type 'long double', but argument 2 has type 'double'

Compiling the same code with avr-gcc gives:

foo.c:8: warning: format '% Lf' expects type 'long double', but argument 2 has type 'float'

Maybe this is an artifact of the AVR-GCC implementation where sizeof(double) = sizeof(float).

Anyway, it's probably good practise to make the type conversion obvious by adding
a typecast to double. Implied type conversions can be dangerous to the innocent
reader of the code.

Strange....
I bet it is something more subtle than a simple type equivalence. Perhaps floats are not being promoted at all?

I'm not sure why having to do the double cast is "good practice". People normally don't cast chars or unsigned chars to int to print with percent d, so to me it seems not normal to have to cast a float for percent f.

I think I'll go have a look and see if I can track this down.

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Perhaps floats are not being promoted at all?

This is hard to tell if your sizeof(float) == sizeof(double) ;-), and
on machines where that doesn't apply, the promotion to double is proven
to work (otherwise, the printf would print garbage since 32-bit and
64-bit IEEE 754 numbers are not bit compatible).

> I'm not sure why having to do the double cast is "good practice".

Because the implied type conversions are often not recognized when you
read the code. They only happen for variadic functions when all your
functions have a proper prototype declaration.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is starting to appear to me that this is a subtle promotion bug when the precision of floats is the same as doubles.
I don't think the compiler has been tested very much when floats are essentially the same a double.

There are cases in the code where conversions to double are only happening if the precision (number of bits) in the REAL_TYPE is less than the precision of a double.

So if a float is the same precision as double, the conversion is not done.

While the size and format of the 2 may be same, I believe that internally they are typed/marked/tracked differently.

For one example:
Take a look at the function convert_arguments() in c-typeck.c

else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
	       && (TYPE_PRECISION (TREE_TYPE (val))
		   < TYPE_PRECISION (double_type_node))
	       && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
        {
	  if (type_generic)
	    argarray[parmnum] = val;
	  else
	    /* Convert `float' to `double'.  */
	    argarray[parmnum] = convert (double_type_node, val);
	}

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> It is starting to appear to me that this is a subtle promotion bug
> when the precision of floats is the same as doubles.

That was my idea, too. However, the only "bug" in that is that the warning
message is wrong (and confusing). There is no erroneous behaviour caused
by that.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't yet verified if this is causing a float to not be promoted.
If it is then it is indeed a bug.

Just because the promotion has no effect on transforming the actual data format and the behavior of the running code will be same, doesn't mean that there isn't some erroneous behavior occurring within the compiler.

The code that sanity checks printf arguments uses exact types. So if this type conversion doesn't happen, it could erroneously report an argument type problem when there shouldn't be because it "sees" a float argument when in fact it should have been a double had it been promoted correctly.

I need to build a version of the compiler that I can run the debugger on to isolate exactly what and were the problem is.

In the mean time, I think a quick and dirty way around this bug is for users
to add this to their code that uses floats:

#define float double

--- bill