以下代码在 32 位和 64 位操作系统中的行为不同。
char *cat = "v,a";
if (strcmp(cat, ",") == 1)
...
上述条件在 32 位中为真,但在 64 位中为假。我想知道为什么这不一样?32 位和 64 位操作系统都是 Linux (Fedora)。
以下代码在 32 位和 64 位操作系统中的行为不同。
char *cat = "v,a";
if (strcmp(cat, ",") == 1)
...
上述条件在 32 位中为真,但在 64 位中为假。我想知道为什么这不一样?32 位和 64 位操作系统都是 Linux (Fedora)。
如果参数 1 在参数 2 之前,则该strcmp()
函数仅定义为返回负值,如果它们相同则返回零,或者如果参数 1 在参数 2 之后,则返回正值。
无法保证返回的值将是+1
或-1
在任何时候。基于该假设的任何相等性测试都是错误的。可以想象,strcmp()
对于给定的字符串比较,32 位和 64 位版本返回不同的数字,但任何寻找+1
from的测试strcmp()
都存在固有缺陷。
您的比较代码应该是以下之一:
if (strcmp(cat, ",") > 0) // cat > ","
if (strcmp(cat, ",") == 0) // cat == ","
if (strcmp(cat, ",") >= 0) // cat >= ","
if (strcmp(cat, ",") <= 0) // cat <= ","
if (strcmp(cat, ",") < 0) // cat < ","
if (strcmp(cat, ",") != 0) // cat != ","
注意一个共同的主题——所有的测试都与 0 比较。你还会看到人们写:
if (strcmp(cat, ",")) // != 0
if (!strcmp(cat, ",")) // == 0
就个人而言,我更喜欢与零进行显式比较;我在心理上将速记翻译成适当的速记(并且讨厌这样做)。
请注意,规范strcmp()
说:
ISO/IEC 9899: 2011 §7.24.4.2功能
strcmp
¶3 该
strcmp
函数返回一个大于、等于或小于零的整数,相应地,因为指向的字符串s1
大于、等于或小于指向的字符串s2
。
它什么也没说+1
or -1
; 你不能依赖结果的大小,只能依赖它的符号(或者当字符串相等时它为零)。
标准函数不会根据您的操作系统的“bittedness”表现出不同的行为,除非您正在做一些愚蠢的事情,例如,不包括相关的头文件。除非您违反规则,否则他们必须完全表现出标准中指定的行为。否则,您的编译器虽然关闭,但不会是 C 编译器。
但是,根据标准, from 的返回值strcmp()
是零、正数或负数,不保证非零时为 +/-1。
你的表达最好写成:
strcmp (cat, ",") > 0
使用strcmp (cat, ",") == 1
错误与您的操作系统是32位还是64位无关,而与您误解了返回值有关。来自 ISO C11 标准(我的粗体):
strcmp 函数返回一个大于、等于或小于零的整数,相应地,因为 s1 指向的字符串大于、等于或小于 s2 指向的字符串。
strcmp()
上面乔纳森的回答很好地解释了由 保证的语义。
回到你原来的问题,即
问。为什么
strcmp()
32 位和 64 位系统的行为不同?
答:strcmp()
在 glibc 中实现,其中存在针对各种架构的不同实现,都针对相应架构进行了高度优化。
由于规范简单地定义了返回值是 3 种可能性之一(-ve、0、+ve),只要符号适当地指示结果,各种实现都可以自由地返回任何值。
在某些架构(在本例中为 x86)上,简单地比较每个字节而不存储结果会更快。因此,在不匹配时简单地返回 -/+1 会更快。
(请注意,可以使用subb
而不是cmpb
在 x86 上获得不匹配字节的大小差异。但这将需要每个字节额外1个时钟周期。这意味着每次完整迭代所需的总时间增加 3%运行时间少于 30 个时钟周期。)
在其他架构(在本例中为 x86-64)上,相应字符的字节值之间的差异已经作为比较的副产品提供。因此,简单地返回它而不是再次测试它们并返回 -/+1 会更快。
两者都是完全有效的输出,因为strcmp()
函数只能保证使用正确的符号返回结果,并且幅度是特定于架构/实现的。