c - "strlen(s1) - strlen(s2)"永远不会小于零

标签 c string debugging unsigned

我目前正在编写一个需要频繁比较字符串长度的 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 编写程序时经常遵守的规则。
  • 不要 使用只是因为数字是非负数。 很容易犯错误,而且这些错误有时非常微妙(如示例 2 所示)。
  • 在执行模运算时使用。
  • 使用位来表示集合时使用。 这通常很方便,因为它允许您在没有符号扩展的情况下执行逻辑右移。

  • 当然,在某些情况下,您可能决定违反这些“规则”。但大多数情况下,遵循这些建议将使您的代码更易于使用且不易出错。

    关于c - "strlen(s1) - strlen(s2)"永远不会小于零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10474769/

    相关文章:

    java - 如何在 Java 中比较字符串?

    java - 如何启用 Mockito 调试消息?

    c - 使用 mdbg 调试带有 Windows SDK 7.1 的简​​单 C 代码

    c - 在C中使用输入的复杂性(观点?)

    连接两个捕获组

    mysql - 使用 Case 语句计算 MYSQL 中子字符串出现的次数

    java - 为什么 "\t"在 Java String.split 中有效,但在 "\."中无效?

    c - 将指针字符打印为十六进制

    c - 这个 C 代码在语法上正确吗?

    wcf - 调试时如何从 WCF 服务内部查看控制台输出?