[英]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 之外的整數; 但它符合標准。
順便說一句,使用GCC和GNU 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.