警告:无符号表达式的比较> = 0始终为true
编译C文件时出现以下错误:
t_memmove.c: In function 'ft_memmove': ft_memmove.c:19: warning: comparison of unsigned expression >= 0 is always true
这是完整的代码,来自cat ft_memmove.c
:
#include "libft.h" #include void *ft_memmove(void *s1, const void *s2, size_t n) { char *s1c; char *s2c; size_t i; if (!s1 || !s2 || !n) { return s1; } i = 0; s1c = (char *) s1; s2c = (char *) s2; if (s1c > s2c) { while (n - i >= 0) // this triggers the error { s1c[n - i] = s2c[n - i]; ++i; } } else { while (i < n) { s1c[i] = s2c[i]; ++i; } } return s1; }
我确实理解size_t是无符号的,并且由于这个原因,两个整数都将> = 0。 但是因为我从另一个中减去一个,所以我不明白。 为什么会出现这个错误?
如果在C中减去两个无符号整数,结果将被解释为无符号。 它不会因为您减去而自动将其视为已签名。 解决这个问题的一种方法是使用n >= i
而不是n - i >= 0
。
根据C99标准通用算术转换草案的第6.3.1.8
节,由于它们属于同一类型,因此结果也将是size_t
。 该节说明:
[…]除非另有明确说明,否则常见的实际类型也是结果的相应实际类型[…]
后来说:
如果两个操作数具有相同的类型,则不需要进一步转换。
在数学上你可以将i
移动到表达式的另一侧,如下所示:
n >= i
考虑这个循环:
for(unsigned int i=5;i>=0;i--) { }
这个循环将是无限的,因为每当我变为-1时,它将被插入为非常大的正确值,因为unsigned int
不存在符号位。
这就是这里产生警告的原因
unsigned
算术结果是unsigned
,这就是你得到这个警告的原因。 最好将n - i >= 0
改为n >= i
。
无符号操作数的操作在无符号类型的域中执行。 无符号算术遵循模运算的规则。 这意味着即使你从某些东西中减去某些东西,结果也永远不会是负面的。 例如1u - 5u
不产生-4
。 如果产生UINT_MAX - 3
,这是一个巨大的正值,与-4
模UINT_MAX + 1
。