传递字符串的指针或文字不一致时strcmp()的返回值 [英] Inconsistent strcmp() return value when passing strings as pointers or as literals

查看:188
本文介绍了传递字符串的指针或文字不一致时strcmp()的返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在玩弄 STRCMP 时,我注意到这一点,这里是code:

 的#include<&string.h中GT;
#包括LT&;&stdio.h中GT;诠释主(){    //传球直接串
    的printf(%d个\\ N,STRCMP(艾哈迈德,澄波));    //传递字符串的指针
    字符* A =艾哈迈德;
    char *之B =澄波;
    的printf(%d个\\ N,STRCMP(A,B));    返回0;}

的输出是:

  -1
-5

不应该 STRCMP 工作一样吗?为什么,我定当我通过字符串作为艾哈迈德不同的值的char * A =艾哈迈德。当值传递给函数他们是在它的堆栈分配权?


解决方案

您最有可能看到一个编译器优化的结果。如果我们测试使用的go​​dbolt 海湾合作委员会code,用 -O0 优化级别,我们可以看到第一种情况下它不叫 STRCMP

  MOVL $ -1%ESI#
MOVL $ .LC0,EDI%#,
MOVL $ 0,%EAX#
调用printf#

由于您使用的是常量作为参数传递给 STRCMP 编译器能够用于执行常量折叠并调用的编译器的内部在编译时并生成 1 然后,而不必调用 STRCMP 在这是在标准库实现,将会有不同的实现,那么一个可能的更简单的编译时间 STRCMP

在第二种情况下它产生一个呼叫 STRCMP

 通话STRCMP#
MOVL%EAX,ESI%#D.2047,
MOVL $ .LC0,EDI%#,
MOVL $ 0,%EAX#
调用printf#

这是与 GCC有STRCMP ,这是 GCC 常量折叠时将使用。

如果我们进一步<一个href=\"http://gcc.godbolt.org/#%7B%22version%22%3A3%2C%22filterAsm%22%3A%7B%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue%2C%22colouriseAsm%22%3Atrue%7D%2C%22compilers%22%3A%5B%7B%22sourcez%22%3A%22MQSwdgxgNgrgJgUwAQB4DOAXOID2A6ACwD4AoUSWRVTAJ3AHNDSTwMkBbAQ3AAoBKAN4kSSUUgD04gA6c0aBkloM0SbDQQQMUAJ4ixUumAwAzHgCIApHAA6YMwBpFGGhHZTznAlzgOkZ45wYCFxmfHwA3MJiEtKy8mD0Tob0KrJIUjisCDQqeqIQBJw0SABUnAC8fp7eZpHRBUWlAEaV%2FoHBnLV56YYm5la2DrSu7pz2TWGR3eoYMDRgSAAMUwC%2BQAA%3D%22%2C%22compiler%22%3A%22%2Fopt%2Fgcc-4.9.0%2Fbin%2Fg%2B%2B%22%2C%22options%22%3A%22-x%20c%20-std%3Dc99%20-O3%20-fverbose-asm%20-fno-inline-small-functions%22%7D%5D%7D\"相对=nofollow>测试使用 -O1 优化级别或更高 GCC 是能够同时折叠案件的结果将是 1 两种情况:

  MOVL $ -1%ESI#
MOVL $ .LC0,EDI%#,
xorl%EAX,EAX%#
调用printf#
MOVL $ -1%ESI#
MOVL $ .LC0,EDI%#,
xorl%EAX,EAX%#
调用printf#

随着越来越多的优化选项中启用了优化器能够确定 A B 指向在已知常数编译时间还有,也可以在编译时计算 STRCMP 的这种情况下,结果也是如此。

我们可以证实, GCC 由具有的 - 这将产生FNO,内置标志,并观察到 STRCMP 对于所有的情况。

略有不同,它不折都使用 -O0 ,但将在<$倍C $ C> -O1 及以上两者。

请注意,任何负面的结果是完全符合的,我们可以通过将C99的标准草案 7.21.4.2 的STRCMP功能,它说(的看重点煤矿的):


  INT STRCMP(为const char * S1,为const char * S2);


  
  

该STRCMP函数返回一个整数大于,等于,或更低
  大于零
,因此作为字符串指向S1大于,
  由S2等于或小于字符串指出。


technosurus指出, STRCMP 指定处理字符串,如果他们分别组成的 unsigned char型的,这是覆盖在C99下<的code> 7.21.1 它说:


  

有关在本节的所有功能,每一个字符应
  除preTED,如果它有unsigned char类型(因此每
  可能的对象重​​新presentation是有效的,具有不同的值)。


I was playing around with strcmp when I noticed this, here is the code:

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

int main(){

    //passing strings directly
    printf("%d\n", strcmp("ahmad", "fatema"));

    //passing strings as pointers 
    char *a= "ahmad";
    char *b= "fatema";
    printf("%d\n",strcmp(a,b));

    return 0;

}

the output is:

-1
-5

shouldn't strcmp work the same? Why is it that I am given different value when I pass strings as "ahmad" or as char* a = "ahmad". When you pass values to a function they are allocated in its stack right?

解决方案

You are most likely seeing the result of a compiler optimization. If we test the code using gcc on godbolt, with -O0 optimization level, we can see for the first case it does not call strcmp:

movl    $-1, %esi   #,
movl    $.LC0, %edi #,
movl    $0, %eax    #,
call    printf  #

Since your are using constants as arguments to strcmp the compiler is able for perform constant folding and call a compiler intrinsic at compile time and generate the -1 then, instead of having to call strcmp at run-time which is implemented in the standard library and will have a different implementation then a likely more simple compile time strcmp.

In the second case it does generate a call to strcmp:

call    strcmp  #
movl    %eax, %esi  # D.2047,
movl    $.LC0, %edi #,
movl    $0, %eax    #,
call    printf  #

This is consistent with the fact that gcc has a builtin for strcmp, which is what gcc will use during constant folding.

If we further test using -O1 optimization level or greater gcc is able to fold both cases and the result will be -1 for both cases:

movl    $-1, %esi   #,
movl    $.LC0, %edi #,
xorl    %eax, %eax  #
call    printf  #
movl    $-1, %esi   #,
movl    $.LC0, %edi #,
xorl    %eax, %eax  #
call    printf  #

With more optimizations options turned on the optimizer is able to determine that a and b point to constants known at compile time as well and can also compute the result of strcmp for this case as well during compile time.

We can confirm that gcc is using builtin function by building with the -fno-builtin flag and observing that a call to strcmp will be generated for all cases.

clang is slightly different in that it does not fold at all using -O0 but will fold at -O1 and above for both.

Note, that any negative result is an entirely conformant, we can see by going to the draft C99 standard section 7.21.4.2 The strcmp function which says (emphasis mine):

int strcmp(const char *s1, const char *s2);

The strcmp function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2.

technosurus points out that strcmp is specified to treat the strings as if they were composed of unsigned char, this is covered in C99 under 7.21.1 which says:

For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).

这篇关于传递字符串的指针或文字不一致时strcmp()的返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆