在C语言中比较负数

5

我遇到了一个我写的程序的问题。程序进入了一个if语句,但实际上不应该进入。 我有两个变量:

size_t len = 5;
int    tmp = -1;

当我执行以下操作时:
if (tmp > len)
    ft_putstr("this is crazy");

我打印出了“这太疯狂了,因为-1对我来说比5小!好的,好的。所以我在我最喜欢的网站上看到了这个

尝试以下操作:

printf("%zu", tmp) 

我看到一个很大的正数。好吧!这可能是我的程序进入上面的if条件语句的原因,但是我该如何使它不进入if条件语句呢?谢谢。


5
因为size_t是无符号整数类型,所以当将其与有符号整数类型进行比较时,会执行无符号比较。 - Tom Karzes
1
尝试使用 if (tmp > 0 && tmp > len) - user3386109
printf("%zu", tmp);引起未定义行为。对于printf,使用正确的格式说明符取决于您。 - M.M
2个回答

10

问题在于您试图将一个无符号的东西与有符号的东西进行比较。这意味着在实际转换之前存在隐式转换。在这种情况下,有符号的数被转换为无符号的数(通常不是人们想要的,因此许多编译器具有在执行此操作时显示警告的选项)。

要以更加正确的方式草率地完成它,您应该编写:

 if( (int)tmp > (int)len )

然而,这忽略了一个事实,即 size_t 的值可能太大,无法用 int 表示。为了严格处理,我们需要考虑到 int 范围与 size_t 范围的组合可能大于任何可用类型。这意味着您需要处理两种情况,可以利用以下事实:如果 tmp<0,则 tmp<len(数学上如此,因为 len>=0)。例如,数学上 tmp<len 可以写成 tmp<0 || tmp<len。相反的是 tmp>=0 && tmp >= len。因此应编写:

 if( tmp >= 0 && tmp > len )

请注意,这时候转换不是一个问题,tmp在第一次检查后可以被转换为无符号数而不改变值,不同范围的intsize_t也不是问题,因为较小值在比较之前会被转换为更宽的范围。

现在唯一的问题是,如果你启用了有关有符号无符号比较的警告(以便检测此类错误),它仍然会发出警告。为了解决这个问题,您需要显式地对其进行类型转换,但我们知道将其转换为无符号数不会改变tmp,一旦我们检查到tmp>=0。因此,为了避免警告,您应该编写:

if( tmp >= 0 && (unsigned)tmp > len) )

(unsigned)是因为tmp是一个int,当将其转换为无符号类型时需要考虑类型。


0

你必须理解不同变量类型之间的区别。例如,变量类型如intunsignedsize_t等具有不同的行为,基于这些行为你会得到不同的结果。

如果你真的想要比较两个数字,它们必须在相同的级别(变量类型)上,否则你会得到意外的结果。

以下内容将解决你的问题。

if(tmp > (int)len)
    ft_putstr("this is crazy");

正如@jblixr所建议的(感谢评论),您可能需要注意这些变量类型的sizeof,并确保在将值从一种数据类型转换为另一种数据类型时不会丢失值。

3
你认为这是一个好的解决方案吗?如果 len4294967295 这样大,会发生什么?那么 len 将被看作是一个负数。 - jblixr
@jblixr 如果你指的是 size_tint 的大小,那么不是。 - Pawan
1
一个 size_t 值比 INT_MAX 更大的可能性有多大?不是很大。在大多数情况下,这种比较是可以的。 - Per Johansson
在例如 MS-DOS 下,当使用巨大内存模型时可能会发生这种情况。由于 INT_MAX 为 32767,而 size_t 为 32 位,因此您可能会遇到一些麻烦。即使在某些 64 位操作系统下,现代系统中的 int 也是 32 位,而 size_t 是 64 位(并且有些情况下,size_t 实际上比 2GiB 更大)。我想说,size_t 值大于 INT_MAX 的可能性非常大。 - skyking

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接