To Cast the return value of a function that returns a floating point type to ensure predictable program execution casts to type float must be present on all floating-point function calls.
Wiki Markup |
---|
The C99 standard \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] states in Section 6.8.6.4, Paragraph 3, |
...
Function f
is allowed to return a value wider than float
, but function g
(which uses the wider constant) is not.
Although the current text does not require narrowing return expressions of the same type as the function, it does not clearly state stated what is allowed. Is it allowed to narrow the result? Is it allowed to narrow the result sometimes but not always? Is it allowed to partially narrow the result (e.g.for example, if the ABI returns floats in double format but a float function has a float return expression evaluated to wider than double)? An aggressive implementation could argue âyesâ to all these, though the resulting behavior would complicate debugging and error analysis.
...
Noncompliant Code Example
The following example code has been constructed to illustrate an example that does not conform to this recommendation. The code is nonconforming because it does not This noncompliant code example fails to cast the result of the expression in the return statement and thereby guarantee the range or precision is no wider than expected. The uncertainty in this example is introduced by the constant 0.1f
. This constant may be stored with a range or precision that is greater than that of float. Consequently, the result of x * 0.1f
may also have a range or precision greater than that of float. As described above, this range or precision may not be reduced to that of a float and, thus, the caller of calcPercentage()
may receive a value that is more precise than expected. This may lead to inconsistent program execution across different platforms.
Code Block | ||
---|---|---|
| ||
float calcPercentage(float value) { Â return value * 0.1f; } void floatRoutine(void) { float value = 99.0f; long double percentage; percentage = calcPercentage(value); } |
Compliant
...
Solution
This compliant solution remedies casts The following code example remedies the above noncompliant code by casting the value of the expression in the return statement. This forces the return value to have the expected range and precision as described in Section 5.2.4.2.2 8 of the C Standard.
...
Unfortunately, not all compilers may honor casts. In this case, the range and precision must be forced by assignment to a variable of the correct type. The following code example illustrates this approachThis compliant solution forces the assignment by type qualifying result
as volatile and assigning the result of the floating point operation to result
before returning it.
Code Block | ||
---|---|---|
| ||
float calcPercentage(float value) { volatile float result; result = value * 0.1f; Â return result; } void floatRoutine(void) { float value = 99.0f; long double percentage; percentage = calcPercentage(value); } |
Compliant
...
Solution (Outside the function 1
)
Forcing the range and precision inside the calcPercentage()
function is a good way to fix the problem once without having to apply fixes in multiple locations (every time calcPercentage()
is called). However, access to the called function may not always be available. This example compliant solution shows one way to force the correct range and precision in a situation in which the source of the called function can not be modified. This is accomplished by casting the return value of the calcPercentage()
function to float
.
Code Block | ||
---|---|---|
| ||
void floatRoutine(void) { float value = 99.0f; long double percentage; percentage = (float)calcPercentage(value); } |
Compliant
...
Solution (Outside the function 2)
This example compliant solution shows another way to force the correct range and precision. In this case, a temporary variable is used as the forcing mechanism.
...