0
void main() {
    unsigned int a = 0;
    if (a - 10 < 0) {
        printf("error!\n");
    }
}

we know this comparison won't work, because a-10 will be a big unsigned integer, it can't be smaller than 0.

To avoid this situation, I try this:

void main() {
    unsigned int a = 0;
    int b = 0;// or const int b = 0;
    if (a - 10 < b) {
        printf("error!\n");
    }
}

this will get warning C4018 using Visual Studio 2022 17.2.4.

However, when I use gcc 4.8.5, there is no warning at all.

Is there a way to avoid coder compare signed number with unsigned variable?

Update: a more complex situation could be this:

struct s{
unsigned int len;
char *buffer;
} *a;

int not_safe(struct s *ptr){
 if(ptr->len - sizeof(struct s) < 0){
  return 0;
 }
 return 1;
}

Programmers may not be aware of such comparisons are wrong. I hope we can have a safe way to let programmer avoid this.

VictorV
  • 637
  • 7
  • 16
  • Why not do this? `(int)a - 10` – Itagaki Fumihiko Nov 29 '22 at 02:42
  • @ItagakiFumihiko the coder maybe don't notice it. I hope we can avoid it. – VictorV Nov 29 '22 at 02:57
  • If so, then the coding itself, with the possibility of further subtraction of unsigned a from 0, is wrong in the first place. – Itagaki Fumihiko Nov 29 '22 at 03:01
  • @ItagakiFumihiko I did some update, this wrong operation may happen when many coders work together. – VictorV Nov 29 '22 at 03:16
  • If you add the proper warning option `-Wsign-compare`, you will get a [warning](https://godbolt.org/z/Mj7rhKfec). – ssbssa Nov 29 '22 at 10:50
  • @VictorV I can only conclude that the problem is that you should increase the C proficiency of the colleagues you work with. Whether the result of an operation will overflow or underflow is a run-time thing and cannot be predicted by the compiler. – Itagaki Fumihiko Nov 30 '22 at 00:35

3 Answers3

0

If you cast the unsigned int operand to int:

if ((int)a - 10 < 0)

Then all of the math with be done using type int.

Or, you can do a little bit of algebra:

if (a < 10)

To avoid the problem completely.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • I want to have a safe check(or a safe coding paradigm) to avoid coders do this. They may don't know this is dangerous when they are coding. – VictorV Nov 29 '22 at 02:55
  • 1
    If you compile with `-Wall -Wextra` it should warn about signed/unsigned comparisons. – dbush Nov 29 '22 at 03:00
  • -Wextra works well :) If this parameter sets this parameter, will it add many warnings? – VictorV Nov 29 '22 at 03:12
  • @VictorV Yes, it enables other warnings (see the man pages for details) but this is generally a good thing. I use those options for my code. – dbush Nov 29 '22 at 03:14
  • 1
    @VictorV Regarding gcc warnings, `-Wall -Wextra` only gives warnings of the nature: "hey this is almost certainly a bug". There's also `-Wconversion` that can be used for extra checks, but that one is more fickle and gives warnings like "this may or may not be a bug". – Lundin Nov 29 '22 at 10:17
0

Please study what C formally calls the usual arithmetic conversions Implicit type promotion rules. The TL;DR is that in case you have two integers of the same size but different signedness, the signed one will get converted to unsigned.

You could explicitly cast the unsigned operand to signed. Or you could let the signed operand be a larger type than the unsigned, such as int64_t, in which case the unsigned int (likely 16 or 32 bits) will get converted to int64_t.

But that won't solve your root problem which is this line:

if(ptr->len - sizeof(struct s) < 0)

This is doesn't make any sense to begin with. And casting ptr->len to int64_t might not help either size sizeof returns a size_t, which is guaranteed to be a large unsigned integer type. Simply replace this with:

if(sizeof(struct s) > ptr->len)

Or if you will, change the whole function to one following common best practices:

bool not_safe (const struct s* ptr) {
  return sizeof(struct s) > ptr->len;
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Yes, we can avoid it by coding safely, however, this mistake can also be noticed by compiler, I hope we can find a good way to alert it. Telling a programmer how to write safe codes is not a best way, once they forget, a bug will be created. – VictorV Dec 05 '22 at 04:41
0

Inspired by @dbush.

Add -Werror -Wextra to gcc, -Wextra will alert coder, -Werror will stop build, thus we can stop coder create bug.

VictorV
  • 637
  • 7
  • 16