10

There's a rationale for the warning here, but that fails to answer the whole picture. For example the following code triggers the warning:

(int)round(M_PI);

but on the other hand the following code doesn't:

double d;
(int)(d = round(M_PI));

this doesn't either:

(int)M_PI;

the rationale was that you shouldn't convert to int by simply casting, but you should use round, floor or similar function. However using round will still trigger the warning, but as seen above typecasting a constant or assigned variable doesn't.

So if it's that bad to cast from double to int, then why doesn't the warning trigger when you write (int)d or (int)M_PI? In what way is one supposed to circumvent the warning in case you want to convert the return value? Is there a warning that would handle these perilous conversions in a more correct/reasonable way?

Community
  • 1
  • 1
skyking
  • 13,817
  • 1
  • 35
  • 57

2 Answers2

8

-Wbad-function-cast (C and Objective-C only)

Warn when a function call is cast to a non-matching type. For example, warn if a call to a function returning an integer type is cast to a pointer type.

As its name suggests, -Wbad-function-cast only warns when you are casting function calls to a non-matching type. It doesn't warn on all casts. This explains why you are not getting that warning for your last two examples:

You are right that it could be bad to cast from double to int as you are potentially losing information. You could avoid the GCC warning by simply assigning the function return value to a matching type, then casting later, as in your two examples that don't trigger the warning.

Of course, the point of the warning is not to force you to write extra code to do the same thing. Even for functions that "return an integral value" like round(), the return value may be too big to fit in an int. What you should be doing is checking to see if the value is safe to cast first.

Community
  • 1
  • 1
congusbongus
  • 13,359
  • 7
  • 71
  • 99
  • So, what do you do when the value is manifestly safe to cast to an int, so a test is unnecessary? I'm getting the error for something like: int x = ceil((int)y * sine(r)); This is an integer multiplied by a value less than or equal to 1. I shouldn't have to prove to the compiler that this is valid. – swestrup Nov 25 '19 at 22:08
  • @swestrup The C language isn't sophisticated enough to recognise that functions return values within a fixed range, so it would be impossible for a standards-compliant compiler to know this too. – congusbongus Nov 25 '19 at 22:50
  • Yes, so the diagnostic then MUST produce false positives. Since that is so, why have it? – swestrup Dec 27 '19 at 22:39
0

If you like the warning generally but are annoyed that there's no way to write an explicit cast that suppresses it, on GCC you can do this:

_Pragma ("GCC diagnostic push");                            
_Pragma ("GCC diagnostic ignored \"-Wbad-function-cast\"");
OCR1A = ((uint16_t) (function_returning_double));          
_Pragma ("GCC diagnostic pop");   

I would only resort to this in contexts where you don't want to introduce an intermediate value (i.e. in a macro). As others have noted (in here: What is the purpose of gcc's -Wbad-function-cast?), a gratuitous lrint()/lround() might not get optimized away. And inserting an intermediate value in a macro is unhygienic.

Britton Kerin
  • 427
  • 4
  • 9