strcmp 和 strstr 测试二进制等价性吗?

Do strcmp and strstr test binary equivalence?

https://docs.microsoft.com/en-us/windows/win32/intl/security-considerations--international-features

这个网页让我感到奇怪。 显然,一些 windows api 可能认为两个字符串相等,但实际上它们是不同的字节序列。 我想知道 C 标准库在这方面的表现如何。

换句话说,strcmp(a,b)==0是否意味着strlen(a)==strlen(b)&&memcmp(a,b,strlen(a))==0? 以及其他字符串函数,包括宽字符版本?

编辑:

例如,CompareStringW 等于 L"\x00C5" 和 L"\x212B" printf("%d\n",CompareStringW(LOCALE_INVARIANT,0,L"\x00C5",-1,L"\x212B",-1)==CSTR_EQUAL); 输出 1

我想问的是 C 库函数是否永远不会像这样

  1. 使用不同编码的两个字符串可以相同,即使它们的字节表示不同。
  2. 标准库 strcmp 确实比较普通的“字符”字符串,在这种情况下 strcmp(a,b)==0 implies strlen(a)==strlen(b)&&memcmp(a,b,strlen(a))==0
  3. wcscmp 这样的函数要求两个字符串以相同的方式编码,因此它们的字节表示形式应该相同。

常规字符串函数运行 byte-by-byte。 specification 表示:

The sign of a nonzero value returned by the comparison functions memcmp, strcmp, and strncmp is determined by the sign of the difference between the values of the first pair of characters (both interpreted as unsigned char) that differ in the objects being compared.

strcmp()memcmp() 做同样的比较。唯一的区别是 strcmp() 使用字符串中的空终止符作为限制,memcmp() 为此使用一个参数,而 strncmp() 使用一个限制参数并使用先到者。

宽字符串函数 specification 说:

Unless explicitly stated otherwise, the functions described in this subclause order two wide characters the same way as two integers of the underlying integer type designated by wchar_t.

wcscmp() 没有另外说明,所以它也是在数字上比较宽字符,而不是通过将它们的编码转换为一些常见的字符表示。 wcscmp() 之于 wmemcmp() 如同 strcmp() 之于 memcmp().

另一方面,wcscoll() 比较根据当前语言环境的 LC_COLLATE 类别解释的字符串。所以这可能不等同于 memcmp().

对于其他功能,您应该查看文档以查看它们是否引用了语言环境。

Apparently some windows api may consider two strings equal when they are actually different byte sequences.

根据上下文以及您从何处获取这些字符串,这实际上是语义上正确的行为。

有多种方法可以编码 某些字符。例如,德语 'ä'。在 Unicode 中,这可能是 U+00E4 LATIN SMALL LETTER A WITH DAERHESIS,或者它可能是 U+0308 COMBINING DIAERESIS 和 U+0061 LATIN SMALL LETTER A 的序列。您可能需要一个比较函数来实际比较它们是否相等。或者你可以让它们 not 比较相等,但有一个独立的函数将一种表示转换为另一种表示(“规范化”)。

您可能需要一个比较函数,将 '6'(六)与 '๖'(也是六,仅在泰语中)进行比较。 (“规范化”)

字节字符串函数(strcmp() 等)无法做到这些。他们只处理字节序列,并不知道我上面写的任何东西。

至于宽字符串函数(wcscmp() 等),嗯......它们也不是,真的。

in other words, does strcmp(a,b)==0 imply strlen(a)==strlen(b)&&memcmp(a,b,strlen(a))==0? and what about other string functions, including wide character versions?

两者都将测试二进制等价性,因为 C 标准库中没有规范化或规范化字符串的机制。[1]


如果你实际处理处理字符串(而不是仅仅传递它们,C字节字符串和宽字符串足够了),你应该使用 ICU library事实上的 标准来处理 C/C++ Unicode。这看起来令人生畏,但实际上需要正确处理所有这些事情。

基本上,任何承诺做同样事情的 C/C++ API 要么 使用 ICU 库本身,要么很可能不做它在宣传什么。

[1]:实际上,strcoll() / strxfrm()wcscoll() / wcsxfrm() 实际上提供了足够的摆动空间来挤入适当的 Unicode 机制进行整理,但我不知道有哪个实现会真正费心这样做。