In some embedded C code for the MC9S12C32 microcontroller, I have a circular queue (aka circular buffer) implemented with a statically sized byte array and two "pointers" for the front and rear of the queue, which are in reality just indices for the queue's array.
// call unsigned chars bytes
typedef unsigned char byte;
byte trear = 0; // SCI transmit display buffer IN index
byte tfront = 0; // SCI transmit display buffer OUT index
byte tsize = 16; // size of transmit buffer
byte tbuf[16]= {0};// SCI transmit display buffer
Note that trear
is the actual index of the rear element, but tfront
is one less than actual index of the front element (subject to modulo 16 of course). So, for example, if my buffer contained "hello", it might look like this (where empty slots are garbage values):
_________________________________
| | |h|e|l|l|o| | | | | | | | | |
^ ^
front rear
When it's time to remove a byte from the queue, I do this:
// increment front index
tfront++;
// wrap front index if it exceeded bounds
tfront %= tsize; // (A)
// get character to transmit
byte outputChar = tbuf[tfront];
This all works fine -- at least, my program has exhibited no bugs related to this fragment. However, when I compile this program, my compiler warns me about the line marked (A)
in the fragment above, complaining:
Warning : C2705: Possible loss of data
main.c line 402
Line 402 is line (A). I should note that I am not using gcc or the like; I am compiling in Freescale's CodeWarrior IDE, which has sometimes given me other somewhat mystifying warnings. In an attempt to get rid of the warning, I rewrote the fragment above as:
// increment front index mod tsize
tfront = (tfront + 1 >= tsize) ? 0 : tfront + 1; // (B)
// get character to transmit
byte outputChar = tbuf[tfront];
However, my compiler still emits the same warning, this time about line (B)
. Maybe the compiler is telling me that in the statement (tfront + 1 >= tsize)
, tfront
might be 255 before execution, and overflow. Of course, I know this won't happen, but my compiler doesn't.
If this is the case, though, why was line (A)
an issue? Basically, I'd like to know what the compiler is unhappy about.
Since typing out my question, I've solved it by changing tsize
from a variable type to a preprocessor definition (i.e., #define TSIZE 16
). My question still stands, though.
Some related questions:
unsigned overflow with modulus operator in C
modulus operator with unsigned chars
The compiler warning likely comes from the fact that in tfront %= tsize;
, which is equivalent to tfront = tfront % tsize;
, because of promotion rules in C the expression tfront % tsize
has(*) type int
.
It may silence the compiler if you write tfront = (byte)(tfront % tsize);
instead.
There is no particular reason to worry, and your compiler emits strange warnings indeed: although the expression tfront % tsize
technically has type int
, its values all fit in a byte
because of the way it is computed. Even if the values did not all fit in a byte
, the wrap-around behavior is guaranteed by the C standard for unsigned integer types (so that you would be justified in using this wrap-around behavior on purpose).
(*) unless on your compilation platform int
cannot contain all values that an unsigned char
can take, in which case it would be of type unsigned int
and you probably wouldn't see the warning.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With