C unsigned module causes compiler warning

In some embedded C code for the MC9S12C32 microcontroller, I have a circular queue (or circular buffer) implemented with a static byte array and two โ€œpointersโ€ for the front and back of the queue, which are actually only indexes for the queue 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 back element, but tfront is one less than the actual index of the front element (naturally, modulo 16, of course). For example, if my buffer contains โ€œhiโ€, it might look like this (where empty slots are garbage values):

 _________________________________ | | |h|e|l|l|o| | | | | | | | | | ^ ^ front rear 

When it's time to remove the 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]; 

All this works fine - at least my program did not detect errors associated with this fragment. However, when I compile this program, my compiler warns me about the line marked (A) in the above snippet, complaining:

Warning: C2705: Possible data loss

main.c line 402

Line 402 is line (A). I should note that I am not using gcc or the like; I compile in the Freescale IDE CodeWarrior IDE, which sometimes gave me some few hoax warnings. In an attempt to get rid of the warning, I rewrote the fragment above:

 // 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 issues the same warning, this time about line (B) . Maybe the compiler tells me that in the statement (tfront + 1 >= tsize) , tfront may be 255 before execution and overflow. Of course, I know that this will not happen, but my compiler does not.

If so, why was the problem in line (A) ? Basically, I would like to know that the compiler is unhappy.


After entering my question, I solved it by changing tsize to the type of the variable to define a preprocessor (i.e. #define TSIZE 16 ). However, my question is still standing.


Some related questions:
unsigned overflow with module in C
module operator with unsigned characters

+6
source share
2 answers

The compiler warning is most likely due to the fact that in tfront %= tsize; , which is equivalent to tfront = tfront % tsize; , due to promotion rules in C, the expression tfront % tsize is (*) of type int .

This can silence the compiler if instead write tfront = (byte)(tfront % tsize); .

There isnโ€™t much reason to worry, and your compiler really emits strange warnings: although the expression tfront % tsize technically of type int , its values โ€‹โ€‹all fit into byte due to the way it is calculated. Even if the values โ€‹โ€‹do not all correspond to the byte size, the wrapping behavior is guaranteed by the C standard for unsigned integer types (so that you would be justified when using this wrapping behavior for its intended purpose).

(*) if on your compilation platform int cannot contain all the values โ€‹โ€‹that unsigned char can take, in which case it will be of type unsigned int , and you probably won't see a warning.

+5
source

This particular warning is a known bug in all Codewarrior compilers. A possible loss of data warning is inconsistent and erroneous. Sometimes he warns, because there is a risk of implicit type promotion, sometimes it is not. See discussion . I can confirm that this is also true for CW for S12C (at least until version 5.1, which I use).

You can disable this warning, but I would not recommend it, as it sometimes finds dangerous code along with false warnings. As in your particular case: the warning is correct.

You do arithmetic on small integer types without explicit garbage. Such code is dangerous and possibly contains hidden errors, because C promotes small integers into signed ints. A coding standard such as MISRA-C that provides explicit casts would help here.

In addition, the operator? It can also be dangerous if you do not know how it works. He balances the second and third operands against each other, which, perhaps, was not expected.

Therefore, I suggest changing the code to:

 tfront = (byte)(tfront % tsize); ... if( (byte)(tfront +1) >= tsize) { tfront = 0; } else { tfront++; } 
+3
source

Source: https://habr.com/ru/post/958076/


All Articles