【问题标题】:Is it safe using return String1 - String2 == 0 for equality checking? [duplicate]使用 return String1 - String2 == 0 进行相等检查是否安全? [复制]
【发布时间】:2018-08-09 04:04:01
【问题描述】:

我刚刚创建了这个函数来检查两个字符串之间的相等性,方法是减去它们的整数值

int EQ(const char* CString1, const char* CString2)
{
    return CString1 - CString2 == 0;
}

但是,我不确定这是否是检查 char* 字符串的安全方法

它不适用于数组,因为它们有不同的整数,所以我为此创建了其他函数

int EQA(const char* CString1, const char* CString2){
    if(CString1 == NULL || CString2 == NULL)
        return 0;
    int i = strlen(CString1);
    if(i != strlen(CString2))
        return 0;
    while(i>=0){
        if(CString1[i] != CString2[i])
            return 0;
        --i;
    }
    return 1;
}

我并没有过多地优化我的第二个函数

但是在查看char* 时,我为什么要使用EQA() 或strcmp() 而不是EQ()?

第一个 EQ() 比我之前使用的任何其他标准函数快
所以我真的喜欢使用它

我在其他机器上对其进行了测试,它工作,但 char* 的整数值不同,也
注意到这些整数取决于代码中首先声明的变量,但如果它们具有 same 字符串,则它是 same 整数,这使得这个函数完美运行,那么它是否依赖于编译器?

为什么不同整数?,它仍然安全吗?

编辑:一些答案侧重于调试我的第二个示例,而不是回答我的问题,因此我对其进行了编辑。

【问题讨论】:

  • 你工作太辛苦了strcmp是你需要的。而且你的两个功能都被窃听了。 EQA 检查CString1 是否是CString2 的前缀,所以例如EQA("", "hello") 为真。
  • 尝试重写标准函数作为学习练习是可以的,但在实际代码中却不是这样。
  • 我在发布此内容之前尝试在 EQA 中检查 strlen(),但出于澄清目的我将其删除。 @john,这不是我原来的,但你是对的,因为我不会在实际代码中使用它们,我试图了解它们是如何工作的
  • 请 不要滥用typography。
  • @Tas 不,这不安全。减去两个不指向同一个数组的指针是未定义的行为。

标签: c++ c


【解决方案1】:

两个字符串在字典上相等并不意味着它们存储在相同的内存位置。减去它们的地址来比较它们可能会产生一些错误的结果。如果两个指针不指向同一个数组的元素或不指向数组的最后一个元素,那么指针减法是没有意义的。
我建议使用标准函数strcmp 进行字典字符串比较。

【讨论】:

  • 只是一个旁注:如果CString1 的长度为零或一,则没有UB。
【解决方案2】:

不要检查差异是否为 0,而只需检查它们是否相等。它会给你相同的结果,但是它不会告诉你你的字符串是否不同,但只有当你的字符串存储在同一个地方时(两个相同的字符串可以存储在不同的地方,并且您的测试看起来会有所不同)。

【讨论】:

  • 是的,我现在明白了,谢谢你和所有在这里努力回答我的问题的人,我感谢他们+1,但我必须选择一个指向实际问题的简单答案,你是对的,直接检查相等性,我做了一个无用的函数。 ^^
  • 不一定没用:两个对象可能是«同卵双胞胎»,但我们有兴趣知道它们是否相同(假设:同时占据同一个地方),或者只是彼此的副本。这只是一个不同的问题:-)
  • 重新“您的测试看起来会有所不同”:C 标准不保证这一点。如果a 和b 是指向不同数组的指针,则a-b 的结果不是C 标准定义的。它可能为零。
  • 它可能是一个意外的值或导致错误,但我不相信它可能是 0。然而,这就是为什么我建议他只测试指针是否相等而不是测试是否他们的差是零。
【解决方案3】:

没有。

您可以在内存中的两个不同位置拥有相同字符串的两个副本,但您的方法会说它们是不同的。

char *s1 = "Hello";
char *s2 = strdup(s1);
printf("%d\n", strcmp(s1, s2)); /* prints 0 */
printf("%d\n", s1-s2); /* does not print 0 */

此外,您的EQA 函数存在可怕的错误:EQA("Hello", "h") 将在 CString2 指针之前访问内存。还要考虑如果 CString2 为 NULL 怎么办?

你确定这个while(i>0 && --i) 检查位置 0 吗?我想它会说“你好”和“果冻”是一样的......(确认。位置 0 未检查)

【讨论】:

  • 我将我的问题编辑为我首先使用 strlen() 的原始函数,你说得对,我忘记了 NULL 的事情,我很高兴指出这一点
【解决方案4】:

来自 6.5.6p9(来自 C 标准 - N1570 )

当两个指针相减时,都应该指向同一个数组对象的元素,或者是数组对象最后一个元素的后一个;结果是两个数组的下标之差元素。结果的大小由实现定义,其类型(有符号整数类型)为头文件中定义的ptrdiff_t。

还有来自standard的:-

...如果表达式P和Q分别指向同一个数组对象x的元素x[i]和x[j],则表达式P - Q的值为 i−j;否则,行为未定义。

鉴于标准的这一部分,这是不正确的。(如上所述,您不能确保它们指向相同位置或相同数组的不同位置)当它不遵循时,您的代码中有undefined behavior上面提到的标准。

您也不能检查两个字符串的相等性( 中的 nul 终止数组)减去它们的地址 - 它如何检查地址中内容的相等性?它不能。标准没有免费提供strcmp - 在这种情况下,您可以使用它来比较字符串的内容。

【讨论】:

  • @JohannesSchaub-litb.:如果允许减去 2 个不一定指向同一个数组的不同地址 - 减去地址并得出它们的内容相同的结论是不好的 - 这是无稽之谈。
  • 这些功能仅供学习,顺便谢谢你的回答:)
  • @KiraSama.:你必须使用strcmp 来编写法律代码——这就是我的观点。我希望你能明白我在回答中所说的话
猜你喜欢
  • 1970-01-01
  • 2021-08-22
  • 2018-05-19
  • 1970-01-01
  • 2022-01-13
  • 2014-09-09
  • 2014-01-08
  • 1970-01-01
相关资源
最近更新 更多