Reputation: 1478
I have a piece of fake/sample code:
#include <stdint.h>
uint8_t func(uint16_t val0, uint16_t val1, uint16_t val2)
{
uint8_t r;
val0 += 0x7F;
val1 += (uint16_t)0x7F;
val2 += 0x7FU;
r = (uint8_t)((val0+val1+val2) >> 8);
r <<= (uint8_t)(val2 & 0x3);
return r;
}
Here are the errors I get:
$ gcc -Wall -Wextra -Wconversion -O0 module.c -c -o module.o
module.c: In function 'func':
module.c:6:10: warning: conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
6 | val0 += 0x7F;
| ^~~~
module.c:7:10: warning: conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
7 | val1 += (uint16_t)0x7F;
| ^
module.c:8:10: warning: conversion from 'unsigned int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
8 | val2 += 0x7FU;
| ^~~~~
module.c:10:8: warning: conversion from 'int' to 'uint8_t' {aka 'unsigned char'} may change value [-Wconversion]
10 | r <<= (uint8_t)(val2 & 0x3);
| ^
The example shows some ways I tried to fix the problem (e.g. cast)
Any suggestion?
EDIT:
modified example
Upvotes: 4
Views: 1053
Reputation: 60097
Casts/bitmasks can do the trick.
E.g.,
#include <stdint.h>
uint8_t func(uint16_t val0, uint16_t val1, uint16_t val2)
{
unsigned int r;
val0 = (uint16_t)(val0 + 0x7Fu);
/*val0 = (val0 + 0x7Fu) & 0xFFFF;*/
val1 = (val1 + 0x7Fu) & 0xFFFF;
val2 = (val2+0x7FU) & 0xFFFF;
r = ((0u+val0+val1+val2) >> 8);
r = ( r << (uint8_t)(val2 & 0x3u)) & 0xFF;
return r&0xFF;
}
It might be a good idea to try and avoid shorter-than-int types. Because of integer promotions (sub-int integer types getting promoted to int
), they tend to lead to a lot of -Wconversion
warnings.
Upvotes: 2
Reputation: 215387
This question illustrates why -Wconversion
is so overzealous that it's largely useless.
In C, there is no arithmetic smaller than int
. For example:
val0 += 0x7F;
is evaluated as if it were
val0 = (int)val0 + 0x7F;
The assignment back to val0
without a cast then triggers -Wconversion
. In some sense this is a legitimate warning: the +
operator does not overflow, but assiging the result back may lose part of the result, and the compiler is telling you this (albeit awkwardly).
If you're going to use -Wconversion
, you essentially can't use compound assignment operator (like +=
) with smaller-than-int
types. You need to write out the equivalent form and use a cast to indicate that you intend for the lossy conversion to happen. For instance here you would write:
val0 = (uint16_t)(val0 + 0x7F);
I don't think this is terribly good style, but some coding standards/policies (MISRA, I think, for one) mandate it.
Upvotes: 9