6

As advised by an answer here, I turned on -Wbad-function-cast to see if my code had any bad behavior gcc could catch, and it turned up this example:

unsigned long n;
// ...
int crossover = (int)pow(n, .14);

(it's not critical here that crossover is an int; it could be unsigned long and the message would be the same).

This seems like a pretty ordinary and useful example of a cast. Why is this problematic? Otherwise, is there a reason to keep this warning turned on?

I generally like to set a lot of warnings, but I can't wrap my mind around the use case for this one. The code I'm working on is heavily numerical and there are lots of times that things are cast from one type to another as required to meet the varying needs of the algorithms involved.

Charles
  • 11,269
  • 13
  • 67
  • 105

2 Answers2

5

You'd better to take this warning seriously.

If you want to get integer from floating-point result of pow, it is rounding operation, which must be done with one of standard rounding functions like round. Doing this with integer cast may yield in surprises: you generally loose the fractional part and for instance 2.76 may end up as 2 with integer truncation, just as 2.12 would end up as 2. Even if you want this behavior, you'd better to specify it explicitly with floor function. This will increase readability and supportability of your code.

Konstantin Vladimirov
  • 6,791
  • 1
  • 27
  • 36
  • Yes, I want that behavior, that's why I'm casting. I notice that I get slower code when I add `floor`; in particular, I get `roundsd` then `cvttsd2si` at -O3 rather than simply `cvttsd2si`. Does this do anything for me? (I'm willing to pay the performance penalty -- though this application is speed-sensitive, this particular part is outside the hot loop -- but only if it will do something of value.) – Charles Oct 11 '13 at 15:50
  • If you are (1) targeting on one concrete architecture and (2) understand what are you doing with truncating cast here, then you may ignore or switch off this warning. It is issued in C to warn about cross-platform compatibility and rounding issues. Also if double result of pow overflows maximum integer value, then cast behavior is undefined, while floor behavior is always specified. – Konstantin Vladimirov Oct 11 '13 at 17:55
  • I agree that overflow would give undefined behavior, which is a Bad Thing. (That's why I gave my sample code -- you can see that overflow is not possible here.) Thanks, I'm accepting now. – Charles Oct 12 '13 at 03:12
  • 10
    Recommending floor may improve readability but doesn't actually help. floor() returns a double, (uint32_t)floor() still throws a -Wbad-function-cast – lod Jun 19 '14 at 01:56
  • 2
    We have lrint and llrint in C99 and beyond. Floor in this answer serves just to determine rounding direction. Also even without any rint, with ceil or floor we might still get warning. But we wouldn't get surprises. – Konstantin Vladimirov Sep 21 '14 at 11:59
  • 2
    So how is one supposed to get rid of the warning when `floor` or `trunc` doesn't seem to do the trick? And also this warning only arises if you cast directly from the return value (which can be used to circumvent the warning) - what's the purpose then of the warning? Isn't it as bad to just type `2.76` to `int` if it is via a variable? – skyking Feb 09 '16 at 14:44
2

The utility of the -Wbad-function-cast warning is limited.

Likely, it is no coincidence that neither -Wall nor -Wextra enable that warning. As well as it is not available for C++ (it is C/Objective-C only).

Your concrete example doesn't exploit undefined behavior nor implementation defined behavior (cf. ISO C11, Section 6.3.1.4). Thus, this warning gives you zero benefits.

In contrast, if you try to rewrite your code to make -Wbad-function-cast happy you just add superfluous function calls that even recent GCC/Clang compilers don't optimize away with -O3:

#include <math.h>
#include <fenv.h>
int f(unsigned n)
{
  int crossover = lrint(floor(pow(n, .14)));
  return crossover;
}

(negative example, no warning emitted with -Wbad-function-cast but superfluous function calls)

maxschlepzig
  • 35,645
  • 14
  • 145
  • 182