Since version 1.80, Cppcheck tells me that
Expression 'msg[ipos++]=checksum(&msg[1],ipos-1)' depends on order of evaluation of side effects
in this code sequence (simplified, data
is a variable)
BYTE msg[MAX_MSG_SIZE]; // msg can be smaller, depending on data encoded
int ipos = 0;
msg[ipos++] = MSG_START;
ipos += encode(&msg[ipos], data);
msg[ipos++] = checksum(&msg[1], ipos-1); // <---- Undefined Behaviour?
msg[ipos++] = MSG_END; // increment ipos to the actual size of msg
and treats this as an error, not a portability issue.
It's C code (incorporated into a C++-dominated project), compiled with a C++98-complient compiler, and meanwhile runs as expected for decades. Cppcheck is run with C++03, C89, auto-detect language.
I confess that the code should better be rewritten. But before doing this, I try to figure out: Is it really dependent on evaluation order? As I understand it, the right operand is being evaluated first (it needs to before the call), then the assignment is taking place (to msg[ipos]
) with the increment of ipos
done last.
Am I wrong with this assumption, or is it just a false positive?
This code does indeed depend on evaluation order in a way which is not well defined:
Specifically, it is not specified whether
ipos++
will increment before or afteripos-1
is evaluated. This is because there is no "sequence point" at the=
, only at the end of the full expression (the;
).The function call is a sequence point. But that only guarantees that
ipos-1
happens before the function call. It does not guarantee thatipos++
happens after.It appears the code should be rewritten this way: