Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This noncompliant code example fails to cast the result of the expression in the return statement and thereby guarantee that 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
bgColor#FFcccc
langc
float calcPercentage(float value) {
  return value * 0.1f;
}

void floatRoutine(void) {
  float value = 99.0f;
  long double percentage;

  percentage = calcPercentage(value);
}

...

This compliant solution casts 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.

Code Block
bgColor#ccccff
langc
float calcPercentage(float value) {
  return (float)(value * 0.1f);
}

void floatRoutine(void) {
  float value = 99.0f;
  long double percentage;

  percentage = calcPercentage(value);
}

...

Unfortunately, not all compilers honor casts. In this case, the range and precision must be forced by assignment to a variable of the correct type. This 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
bgColor#ccccff
langc
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);
}

...

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 compliant solution shows one way to force the correct range and precision in a situation in which the source of the called function cannot be modified. This is accomplished by casting the return value of the calcPercentage() function to float.

Code Block
bgColor#ccccff
langc
void floatRoutine(void) {
  float value = 99.0f;
  long double percentage;

  percentage = (float)calcPercentage(value);
}

...

This compliant solution shows another way to force the correct range and precision. In this case, a temporary variable is used as the forcing mechanism.

Code Block
bgColor#ccccff
langc
void floatRoutine(void) {
  float value = 99.0f;
  long double percentage;
  float temp;

  percentage = temp = calcPercentage(value);
}

...