我目前正在编写一个需要频繁比较字符串长度的 C 程序,所以我编写了以下帮助函数:
int strlonger(char *s1, char *s2) {
return strlen(s1) - strlen(s2) > 0;
}
我注意到该函数即使在
s1
时也返回 true长度比 s2
短.有人可以解释这种奇怪的行为吗?
最佳答案
您遇到的是在处理包含有符号和无符号数量的表达式时在 C 中出现的一些特殊行为。
当在一个操作数有符号而另一个操作数无符号的情况下执行操作时,C 会将有符号参数隐式转换为无符号参数,并假设数字为非负数来执行操作。对于诸如 <
之类的关系运算符,此约定通常会导致不直观的行为。和 >
.
关于你的辅助函数,请注意,因为 strlen
返回类型 size_t
(无符号量),差值和比较均使用无符号算术计算。当s1
短于 s2
,区别strlen(s1) - strlen(s2)
应该是负数,而是变成一个大的无符号数,它大于 0
.因此,
return strlen(s1) - strlen(s2) > 0;
返回
1
即使 s1
短于 s2
.要修复您的函数,请改用以下代码:return strlen(s1) > strlen(s2);
欢迎来到 C 的奇妙世界! :)
其他示例
由于这个问题最近受到了很多关注,我想提供一些(简单的)例子,以确保我能理解这个想法。我将假设我们正在使用使用二进制补码表示的 32 位机器。
在 C 中使用无符号/有符号变量时要理解的重要概念是,如果在单个表达式中混合有无符号和有符号数量,则有符号值将隐式转换为无符号。
示例#1:
考虑以下表达式:
-1 < 0U
由于第二个操作数是无符号的,第一个被隐式转换为无符号,因此表达式等效于比较,
4294967295U < 0U
这当然是假的。这可能不是您期望的行为。
示例#2:
考虑以下尝试对数组
a
的元素求和的代码,其中元素的数量由参数 length
给出:int sum_array_elements(int a[], unsigned length) {
int i;
int result = 0;
for (i = 0; i <= length-1; i++)
result += a[i];
return result;
}
此函数旨在演示从有符号到无符号的隐式转换是多么容易出现错误。传递参数
length
似乎很自然作为未签名;毕竟,谁会想要使用负长度?停止准则 i <= length-1
也似乎很直观。但是,当使用参数 length
运行时等于 0
,这两者的结合产生了意想不到的结果。由于参数
length
是无符号的,计算0-1
使用无符号算术进行,相当于模加法。结果就是 UMax。 <=
比较也是使用无符号比较来执行的,因为任何数字都小于或等于 UMax,所以比较总是成立。因此,代码将尝试访问数组 a
的无效元素。 .可以通过声明
length
来修复代码。成为 int
,或通过更改 for
的测试循环是 i < length
.结论:什么时候应该使用无符号?
我不想在这里说明任何太有争议的内容,但这里有一些我在用 C 编写程序时经常遵守的规则。
当然,在某些情况下,您可能决定违反这些“规则”。但大多数情况下,遵循这些建议将使您的代码更易于使用且不易出错。
关于c - "strlen(s1) - strlen(s2)"永远不会小于零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10474769/