GNU/Linux >> Belajar Linux >  >> Linux

Deklarasi qsort_r berbeda di Mac dan Linux

Apakah akan efektif untuk mengeluh di suatu tempat untuk menyelesaikan masalah ini?

Sayangnya, tidak. Sudah terlalu lama seperti ini dan terlalu banyak kode yang mengandalkannya.

Saya pikir pertanyaan dasarnya adalah "mengapa ketidakcocokan ini terjadi "? Saya akan menjawabnya. Tampaknya bermuara pada BSD yang mengimplementasikannya terlebih dahulu tetapi dengan antarmuka yang buruk. ISO dan kemudian GNU memperbaiki antarmuka dan memutuskan bahwa kerusakan kompatibilitas tidak sia-sia. Dan Microsoft melakukan apa pun yang mereka suka.

Seperti yang ditunjukkan oleh @Downvoter (nama bagus), qsort_r adalah fungsi non-standar. Akan lebih baik jika itu standar, tetapi Anda tidak dapat mengandalkannya. qsort_s adalah semacam standar dalam C11 Annex K, tetapi tidak ada yang benar-benar mengimplementasikan C11, apalagi lampirannya, dan apakah Annex K adalah ide yang bagus masih dipertanyakan.

Seperti banyak masalah C dan Unix, ini disebabkan oleh BSD vs GNU vs Microsoft dan ketidakmampuan mereka untuk mengoordinasikan ekstensi C. Linux adalah GNU. OS X adalah campuran dari banyak hal, tetapi untuk C mengikuti BSD.

FreeBSD menambahkan qsort_r pada September 2002. Visual Studio 2005 menampilkan qsort_s yang sedikit berbeda . ISO memformalkan qsort_s yang berbeda lagi pada tahun 2007. Akhirnya GNU datang bertahun-tahun kemudian di glibc 2.8 pada tahun 2008 tampaknya mengikuti ISO. Ini adalah utas lama dari tahun 2004 hingga 2008 yang meminta qsort_r diimplementasikan dalam glibc yang memiliki beberapa alasan.

Untuk mengingatkan semua orang, ini adalah qsort sebagaimana didefinisikan dalam C99.

void qsort(
    void *base, size_t nmemb, size_t size,
    int (*compar)(const void *, const void *)
);

FreeBSD adalah yang pertama pada September 2002. Mereka memutuskan bahwa qsort_r harus memecahkan qsort antarmuka dan letakkan argumen "thunk" sebelum fungsi perbandingan.

void qsort_r(
    void *base, size_t nmemb, size_t size,
    void *thunk,
    int (*compar)(void *, const void *, const void *)
);

Mengapa? Anda harus bertanya kepada Garrett Wollman yang menulis tambalan itu. Melihat tambalannya Anda dapat melihat dari perubahannya menjadi CMP diputuskan bahwa melakukan "pemikiran" terlebih dahulu adalah pola yang baik. Mungkin mereka memutuskan "fungsi perbandingan ada di bagian akhir" adalah apa yang akan diingat orang. Sayangnya ini berarti qsort dan qsort_r fungsi perbandingan memiliki argumen mereka terbalik. Sangat membingungkan.

Sedangkan Microsoft, yang pernah menjadi inovator, memiliki qsort_s dalam Visual Studio 2005.

void qsort_s(
   void *base, size_t num, size_t width,
   int (__cdecl *compare )(void *, const void *, const void *),
   void * context
);

"s" untuk "aman" daripada "r" untuk "reentrant" yang digunakan orang lain mungkin mengikuti konvensi ISO (lihat di bawah) atau sebaliknya. Mereka meletakkan "thunk" di akhir qsort_s , menjaga argumen tetap sama dengan qsort , tetapi untuk kebingungan maksimum, "thunk" digunakan di awal fungsi perbandingan seperti BSD. Mereka memilih opsi yang paling buruk.

Lebih buruk lagi, pada tahun 2007 ISO menerbitkan TR 24731-1 untuk menambahkan pemeriksaan batas ke perpustakaan standar C (terima kasih @JonathanLeffler untuk menunjukkannya). Dan ya, mereka punya qsort_r sendiri , tetapi disebut qsort_s ! Dan ya, ini berbeda dari milik orang lain!

errno_t qsort_s(
    void *base, rsize_t nmemb, rsize_t size,
    int (*compar)(const void *x, const void *y, void *context),
    void *context
);

Mereka dengan bijak memutuskan untuk menyimpan argumen ke qsort_s dan fungsi perbandingannya merupakan superset dari qsort mungkin berdebat akan lebih mudah bagi orang untuk mengingat. Dan mereka menambahkan nilai pengembalian, mungkin ide yang bagus. Untuk menambah kebingungan, pada saat itu adalah "Laporan Teknis" dan bukan bagian dari standar C. Sekarang menjadi "Lampiran K" dari standar C11, masih opsional tetapi lebih berbobot.

GNU memutuskan hal yang sama, mungkin mengikuti qsort_s ISO .

void qsort_r(
    void *base, size_t nmemb, size_t size,
    int (*compar)(const void *, const void *, void *),
    void *arg
);

Melihat tambalan glibc menambahkan qsort_r itu mungkin juga lebih mudah untuk diimplementasikan. Untuk mengetahui dengan pasti, Anda harus bertanya kepada Ulrich Drepper.

Keputusan BSD untuk menukar argumen dengan qsort dan fungsi perbandingannya mungkin telah menyebabkan banyak kebingungan dan bug selama bertahun-tahun. Keputusan ISO / GNU untuk mempertahankannya bisa dibilang lebih baik. ISO memutuskan untuk memberinya nama yang berbeda. GNU memutuskan untuk menghentikan kompatibilitas dengan fungsi BSD. Microsoft memutuskan untuk melakukan apapun. Sekarang kita terjebak dengan empat implementasi yang tidak kompatibel. Karena fungsi perbandingan memiliki tanda tangan yang berbeda, makro kompatibilitas tidak dapat diabaikan.

(Ini semua adalah rekonstruksi dari kode. Untuk alasan sebenarnya, Anda harus menggali melalui arsip milis.)

Saya tidak bisa menyalahkan GNU atau BSD atau ISO atau Microsoft ... oke, saya bisa menyalahkan Microsoft karena sengaja mencoba mematikan C. Intinya adalah proses standarisasi C, dan memperluas standar itu, dan membuat kompiler mengikuti standar itu adalah sangat lambat dan penulis kompiler terkadang harus melakukan apa yang perlu dilakukan.


Seperti yang tertulis di sini, qsort distandarisasi (C99), tetapi qsort_r adalah ekstensi GNU ("qsort_r() telah ditambahkan ke glibc dalam versi 2.8"). Jadi, tidak ada persyaratan untuk itu sama di semua platform, apalagi portabel.


Linux
  1. Cara menggunakan Mac untuk membuat Linux Live USB Stick dan Boot it

  2. Dalam bahasa apa Windows, Mac OS X dan Linux ditulis?

  3. Pencarian dan penggantian rekursif dalam file teks di Mac dan Linux

  1. Linuxbrew – Manajer Paket Umum Untuk Linux dan Mac OS X

  2. Linux – Menjalankan Aplikasi Mac Os X Di Linux?

  3. Nilai hash berbeda dibuat di windows, linux dan Mac untuk gambar yang sama

  1. Linux – Apakah Kernel Linux/unix yang Berbeda Dapat Dipertukarkan?

  2. Instal python-openstackclient di Linux dan Mac OS

  3. Apa perbedaan antara env dan set (di Mac OS X atau Linux)?