簡體   English   中英

這是 C 中 strcmp() 的唯一返回值嗎?

[英]Is this the only return value for strcmp() in C?

我正在學習 C,目前正在學習字符串處理。 從我學習的地方, strcmp()被定義為-

這是一個比較兩個字符串以確定它們是否相同或不同的函數。 兩個字符串逐個字符地進行比較,直到出現不匹配或到達其中一個字符串的結尾,以先發生者為准。 如果兩個字符串相同,則 strcmp() 返回值零。 如果不是,則返回第一個不匹配字符對的 ASCII 值之間的數字差異。

給出了一個示例程序,這就是我的問題-

main( )
{
    char string1[ ] = "Jerry" ;
    char string2[ ] = "Ferry" ;
    int i, j, k ;
    i = strcmp ( string1, "Jerry" ) ;
    j = strcmp ( string1, string2 ) ;
    k = strcmp ( string1, "Jerry boy" ) ;
    printf ( "\n%d %d %d", i, j, k ) ;
}

我在我的 Windows(64 位)機器上的 Dev-C++ 上運行了這個程序,並得到了這個輸出 - 0 1 -1

現在,這本書給出的輸出為0 4 -32 ,基於這個推理-

在第一次調用 strcmp() 時,兩個字符串是相同的——“Jerry”和“Jerry”——並且 strcmp() 返回的值為零。 在第二次調用中,“Jerry”的第一個字符與“Ferry”的第一個字符不匹配,結果為 4,這是 'J' 的 ASCII 值與 'F' 的 ASCII 值之間的數字差異。 在第三次調用 strcmp( ) 時,“Jerry”與“Jerry boy”不匹配,因為“Jerry”末尾的空字符與“Jerry boy”中的空白不匹配。 返回值為-32,即空字符的值減去空格的ASCII值,即'\\0'減去' ',等於-32。

為了確認書中所說的,我將這段代碼添加到我的程序中,只是為了驗證 J 和 F 之間的 ASCII 差異:

printf("\n Ascii value of J is %d", 'J' );
printf("\n Ascii value of F is %d", 'F' );

然后我相應地在輸出中得到了這個 -

 Ascii value of J is 74
 Ascii value of F is 70

這是根據書中所說的,但是,正如您所看到的,我得到了不同的 j 和 k 值,也就是說,當字符串不匹配時。 我確實在 SO 上查找了類似的問題,並得到了其中一些,但無法找到不同輸出的明確答案(當它返回1 and -1 ),因此我決定提出一個新問題。

這里的這個問題好像有點類似,問題描述中包含了以下關於strcmp() ——

如果發現 s1(或其前 n 個字節)分別小於、匹配或大於 s2,則 strcmp() 和 strncmp() 函數返回一個小於、等於或大於零的整數

在其中一個答案中,我遇到了這個鏈接該鏈接記錄了strcmp()的功能。 它還說——

strcmp() 函數會將 s1 指向的字符串與 s2 指向的字符串進行比較。

非零返回值的符號應由被比較的字符串中不同的第一對字節(均被解釋為無符號字符類型)的值之間的差值的符號確定。

返回值

完成后,如果 s1 指向的字符串大於、等於或小於 s2 指向的字符串,則 strcmp() 將分別返回一個大於、等於或小於 0 的整數。

因此,在閱讀完所有這些之后,我傾向於認為無論使用的實現/平台如何, strcmp()函數都應該僅用於將返回值視為三個類別之一( 0, positive and negative ),而不是依賴於返回的確切值。

我的理解正確嗎?

這是來自 Apple 的 libc 的 C 語言中strcmp()的簡單實現:

int
strcmp(const char *s1, const char *s2)
{
    for ( ; *s1 == *s2; s1++, s2++)
        if (*s1 == '\0')
            return 0;
    return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1);
}

FreeBSD 的 libc 實現:

int
strcmp(const char *s1, const char *s2)
{
    while (*s1 == *s2++)
        if (*s1++ == '\0')
            return (0);
    return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}

這是 GNU libc 的實現,它返回字符之間的差異:

int
strcmp (p1, p2)
     const char *p1;
     const char *p2;
{
  const unsigned char *s1 = (const unsigned char *) p1;
  const unsigned char *s2 = (const unsigned char *) p2;
  unsigned char c1, c2;

  do
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0')
    return c1 - c2;
    }
  while (c1 == c2);

  return c1 - c2;
}

這就是為什么我讀過的大多數比較都寫在< 0 , == 0> 0如果它不需要知道字符串中字符之間的確切區別。

完成后,如果 s1 指向的字符串大於、等於或小於 s2 指向的字符串,則 strcmp() 將分別返回一個大於、等於或小於 0 的整數。

你寫:

因此,在閱讀完所有這些之后,我傾向於認為 0、1 或 -1 是 strcmp() 函數唯一可能的結果。

為什么? 正是沒有指定返回整數的實際值,只指定了它的符號。

C 語言規范是用英文編寫的文檔

標准化委員會的成員仔細選擇他們的話,允許實施者做出自己的實施選擇。

在某些硬件(或實現)上,返回任何整數(尊重規范的約束)可能比僅返回 -1、0、1(如dvm 的答案中提出的函數)更快(或更簡單或更小的代碼)。 FWIW, musl-libc 的strcmp.c更短,並且可以返回 -1、0、1 之外的整數; 但它符合標准。

順便說一句,使用GCCGNU libc (例如在大多數 Linux 系統上), strcmp函數可以被處理 - 特別是在優化時 - 作為編譯器內置- __builtin_strcmp ...然后有時可以用一些非常有效的代碼替換它。

嘗試編譯以下函數(在文件abc.c

#include <string.h>
int isabc(const char*s) { return strcmp(s, "abc"); }

啟用優化並查看匯編代碼。 在我的帶有 GCC 4.9.1 的 Debian/Sid/x86-64 上,使用gcc -fverbose-asm -S -O2 abc.c我在生成的abc.s gcc -fverbose-asm -S -O2 abc.c看不到任何函數調用(但是isabc可能返回其他數字比 -1, 0, 1)。

你應該關心可移植代碼,因此你不應該期望一個特定的值(只要你的供應商的strcmp遵守其不精確和模糊的規范)

另請閱讀未定義行為,這是一個相關的想法:語言規范自願不精確以允許各種實現者進行不同的實現選擇

0, 1, -1就像標准值; 但是,您應該考慮以下這些: zero, positive, negative

在這種情況下,含義是:

  • Zero (0) 表示字符串相等。
  • Negative (-1 或任何其他)表示第一個字符串是less
  • Positive (1 或任何其他)意味着第一個字符串是more

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM