Saya mencoba menerapkan kembali strcasecmp
fungsi dalam C dan saya perhatikan apa yang tampak sebagai inkonsistensi dalam proses perbandingan.
Dari man strcmp
Fungsi strcmp () membandingkan dua string s1 dan s2. Lokal tidak diperhitungkan (untuk perbandingan sadar-lokal, lihat strcoll (3)). Ini mengembalikan bilangan bulat kurang dari, sama dengan, atau lebih besar dari nol jika s1 ditemukan, masing-masing, lebih kecil dari, untuk mencocokkan, atau lebih besar dari s2.
Dari man strcasecmp
Fungsi strcasecmp () melakukan perbandingan byte-by-byte dari string s1 dan s2, mengabaikan case dari karakter. Ini mengembalikan bilangan bulat kurang dari, sama dengan, atau lebih besar dari nol jika s1 ditemukan, masing-masing, lebih kecil dari, untuk mencocokkan, atau lebih besar dari s2.
int strcmp(const char *s1, const char *s2);
int strcasecmp(const char *s1, const char *s2);
Mengingat, informasi ini, saya tidak mengerti hasil dari kode berikut:
#include <stdio.h>
#include <string.h>
int main()
{
// ASCII values
// 'A' = 65
// '_' = 95
// 'a' = 97
printf("%i\n", strcmp("A", "_"));
printf("%i\n", strcmp("a", "_"));
printf("%i\n", strcasecmp("A", "_"));
printf("%i\n", strcasecmp("a", "_"));
return 0;
}
Ouput:
-1 # "A" is less than "_"
1 # "a" is more than "_"
2 # "A" is more than "_" with strcasecmp ???
2 # "a" is more than "_" with strcasecmp
Tampaknya, jika karakter saat s1
ini dalam huruf, itu selalu dikonversi menjadi huruf kecil, terlepas dari apakah karakter saat ini dis2
ini dalam huruf atau tidak.
Adakah yang bisa menjelaskan perilaku ini? Bukankah seharusnya baris pertama dan ketiga identik?
Terima kasih sebelumnya!
PS:
Saya gcc 9.2.0
pakai di Manjaro.
Juga, ketika saya mengkompilasi dengan -fno-builtin
bendera yang saya dapatkan sebagai gantinya:
-30
2
2
2
Saya kira itu karena program tidak menggunakan fungsi gcc yang dioptimalkan, tetapi pertanyaannya tetap.
printf("%i\n", strcasecmp("a", "_"));
Ini mungkin seharusnya memiliki hasil yang sama denganprintf("%i\n", strcasecmp("A", "_"));
Tapi itu berarti bahwa salah satu dari dua panggilan case-sensitive ini akan tidak setuju dengan rekannya yang case-sensitive.strcasecmp
Anda maksud tidak akurat. Detail lebih lanjut dalam jawaban yang dipilih.A < _ && a > _ && A == a
akan menyebabkan banyak masalah.unsigned char
. C17 / 18 "Penanganan string <string.h>" -> "Untuk semua fungsi dalam sub-ayat ini, setiap karakter harus ditafsirkan seolah-olah memiliki tipeunsigned char
". Ini membuat perbedaan begituchar
nilai berada di luar rentang ASCII 0-127.Jawaban:
Perilaku itu benar.
Per spesifikasi POSIX
str\[n\]casecmp()
:Itu juga bagian dari bagian CATATAN pada halaman manual Linux :
Mengapa?
Seperti @HansOlsson tunjukkan dalam jawabannya , melakukan perbandingan case-insensitive antara hanya huruf dan memungkinkan semua perbandingan lainnya memiliki hasil "alami" seperti yang dilakukan pada
strcmp()
akan memecah penyortiran.Jika
'A' == 'a'
(definisi perbandingan case-insensitive) kemudian'_' > 'A'
dan'_' < 'a'
(hasil "alami" dalam rangkaian karakter ASCII) tidak bisa keduanya benar.sumber
'_' > 'A' && '_' < 'a'
; sepertinya bukan contoh terbaik.'a' == 'A'
menurut definisi , jika Anda melakukan perbandingan antara nilai-nilai "alami" dari'a'
,,'A'
dan'_
', Anda tidak dapat melakukan perbandingan case-insensitive antara'A'
dan'a'
untuk mendapatkan kesetaraan dan mendapatkan hasil sortir yang konsisten.'a'
,,'A'
dan'_'
, melalui semua 6 perintah penyisipan ke dalam pohon, dan membandingkan hasil dari "huruf kecil selalu" seperti yang ditentukan untuk pertanyaan yang diajukan "hanya mengkonversi huruf ketika itu perbandingan surat ke surat ". Sebagai contoh, menggunakan algoritma yang terakhir dan mulai dengan'_'
,'a'
dan'A'
berakhir di sisi berlawanan dari pohon namun mereka didefinisikan sebagai sama. Algoritma "hanya mengonversi huruf menjadi huruf kecil dalam perbandingan huruf-huruf" rusak dan 3 karakter tersebut menunjukkan hal itu.'_' > 'A'
dan'_' < 'a'
tidak bisa keduanya benar" tanpa memberi tahu kita mengapa kita berpikir itu akan terjadi. (Itu tugas penjawab, bukan untuk satu dari jutaan pembaca.)Tautan lain, http://man7.org/linux/man-pages/man3/strcasecmp.3p.html untuk strcasecmp mengatakan bahwa mengonversi ke huruf kecil adalah perilaku yang benar (setidaknya di lokal POSIX).
Alasan untuk perilaku itu adalah bahwa jika Anda menggunakan strcasecmp untuk mengurutkan array string diperlukan untuk mendapatkan hasil yang masuk akal.
Kalau tidak, jika Anda mencoba mengurutkan "A", "C", "_", "b" menggunakan misalnya, qsort hasilnya akan tergantung pada urutan perbandingan.
sumber
Itu benar - dan itulah yang harus dilakukan
strcasecmp()
fungsi ! Ini adalah fungsi, bukan bagian dari Standar tetapi, dari " Spesifikasi Basis Grup Terbuka, Edisi 6 ":POSIX
C
Kebetulan, perilaku ini juga berkaitan dengan
_stricmp()
fungsi (seperti yang digunakan dalam Visual Studio / MSCV):sumber
ASCII kode desimal untuk
A
adalah65
untuk_
adalah95
dan untuka
ini97
, jadistrcmp()
itu melakukan apa itu rasa untuk melakukan. Berbicara leksikografis_
lebih kecila
dan lebih besar dariA
.strcasecmp()
akan dianggapA
sebagaia
*, dan karenaa
lebih besar dari_
output juga benar.* Standar POSIX.1-2008 mengatakan fungsi-fungsi ini (strcasecmp () dan strncasecmp ()):
Sumber: http://man7.org/linux/man-pages/man3/strcasecmp.3.html
sumber
A
adalah "lebih besar" daripada_
ketika membandingkan case-insensitive, dan bertanya-tanya mengapa hasilnya tidak sama seperti ketika membandingkan case-sensitive.Since
strcasecmp () `adalah case-sensitive yang akan menganggap A sebagai a` adalah deduksi yang tidak valid. Rutin tidak peka huruf besar-kecil dapat memperlakukan semua huruf besar seolah-olah mereka huruf kecil, bisa memperlakukan semua huruf kecil seolah-olah mereka huruf besar, atau bisa memperlakukan setiap huruf besar sama dengan huruf kecil yang sesuai dan sebaliknya, tetapi masih membandingkannya ke karakter non-huruf dengan nilai mentahnya. Jawaban ini tidak menyatakan alasan untuk memilih salah satu dari kemungkinan-kemungkinan tersebut (alasan yang benar untuk mana dokumentasi mengatakan menggunakan huruf kecil).