使用memcmp比较两个字符串字面值

8
我使用memcmp函数比较了两个字符串字面值。
#include <stdio.h>
#include <string.h>

int main() 
{
  char str1[] = "abcd";
  char str2[] = "ab";

  if (memcmp(str1, str2, 4) == 0) 
  {
    printf("equal string\n");
  }
  return 0;
}

在上面的程序中,str2str1 短。这意味着字符串 str2 超出了边界访问。
那么,这是未定义行为吗?

2
挑剔一点,但你没有比较字面值。你比较了两个具有与字面值相同内容的本地数组。 - StoryTeller - Unslander Monica
2
@StoryTeller:聪明鬼;-) - Bathsheba
2个回答

11

你的代码行为是未定义的。C标准并不要求memcmp在结果已知时立即返回;也就是说,尽管对于语言支持的任何字符编码,'c' == '\0'的值为0,但它不一定在将\0'c'进行比较时返回。标准还没有指定词典比较的顺序(尽管一个实现不从开头开始会很棘手)。

str2 是一个 char[3] 类型。有可能会尝试访问第四个元素。

参考: http://en.cppreference.com/w/c/string/byte/memcmp


1
当条件为真时,一个标准库实现者如果在结果已知后继续处理,那么他是一个糟糕的实现者...并且应该感到羞愧。 - StoryTeller - Unslander Monica
3
当询问未定义行为时,预计最糟糕的库、编译器和机器架构,以及最愚蠢的实现方式 :) - user2371524
2
@StoryTeller:我在想,随着并行化的不断增加,未来的实现是否可以通过预读来获得收益。 - Bathsheba
1
@FelixPalmen - 这是一个激进的想法;) - StoryTeller - Unslander Monica
4
@StoryTeller 图书馆不需要通过 char 指针访问内存。更有可能的是,该库的设计是通过 34 或 64 位宽度访问内存,只要剩余的序列足够宽且正确对齐,仅有错误对齐的第一个字节和最后无法适应此大小的字节会按单字节粒度进行比较。在这个例子中,很可能使用单个32位比较来比较内存。 - Rudi
显示剩余7条评论

-2

是的,您的代码行为是未定义的。但是只要您使用 if (memcmp(str1, str2, 3) == 0)(请注意字节计数为3而不是4,即至少两个),您的代码行为将是可接受和正确的。

如果访问超出 lhs 和 rhs 指向的任一对象的末尾,则其行为是未定义的。如果 lhs 或 rhs 是空指针,则其行为是未定义的。

对于 strcmp,它会在找到 \0 后立即停止。然而,对于 memcmp,

这是一个错误的假设,即 memcmp 逐字节比较并且不查看第一个差异点之后的字节。memcmp 函数没有这样的保证。在报告比较结果之前,它允许读取来自两个缓冲区的所有字节。

因此,我会像这样编写我的代码:

#include <stdio.h>
#include <string.h>

#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))

int main() 
{
  char str1[] = "abcd";
  char str2[] = "ab";
  int charsToCompare = MIN(strlen(str1), strlen(str2)) + 1;

  if (memcmp(str1, str2, charsToCompare) == 0) 
  {
    printf("equal string\n");
  }
  return 0;
}

可以在这里找到关于memcmp的更多细节和分析。


1.) str2的大小是3,而不是2 2.) 请为您的引用添加一个参考。 - user2371524
@FelixPalmen 2 表示您想要比较的字节数。它不是字符串的长度。 - Sandeep
@FelixPalmen 我明白你的意思了。我已经更正了我的回答。谢谢。 - Sandeep
1
谢谢,不过你引用的来源在哪里?我在 C 标准的memcmp()描述中没找到,所以我真的很好奇它来自哪里。 - user2371524
1
那个 MIN 宏最终会为其中一个字符串调用两次 strlen,而这是没有必要的。 - StoryTeller - Unslander Monica
显示剩余2条评论

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