Pertanyaan Bagaimana cara membatasi dampak fitur bahasa tergantung implementasi pada C ++?


Berikut ini adalah kutipan dari buku Bjarne Stroustrup, The C ++ Programming Language:

Bagian 4.6:

Beberapa aspek dari tipe-tipe fundamental C ++, seperti ukuran int, adalah implementasi yang ditentukan (§C.2). Saya menunjukkan ketergantungan ini dan sering merekomendasikan menghindarinya atau mengambil langkah untuk meminimalkan dampaknya. Kenapa kamu repot-repot? Orang yang memprogram berbagai sistem atau menggunakan berbagai kompilator sangat peduli karena jika mereka tidak melakukannya, mereka terpaksa membuang waktu untuk mencari dan memperbaiki bug yang tidak jelas. Orang-orang yang mengklaim bahwa mereka tidak peduli tentang portabilitas biasanya melakukannya karena mereka hanya menggunakan satu sistem dan merasa mereka mampu membayar sikap bahwa 'bahasa adalah apa yang dikompilasi oleh kompilator saya. ’' Ini adalah pandangan sempit dan picik. Jika program Anda sukses, kemungkinan porting, sehingga seseorang harus mencari dan memperbaiki masalah yang terkait dengan fitur yang bergantung pada implementasi. Selain itu, program sering perlu dikompilasi dengan kompiler lain untuk sistem yang sama, dan bahkan rilis kompiler favorit Anda di masa mendatang dapat melakukan beberapa hal berbeda dari yang sekarang. Jauh lebih mudah untuk mengetahui dan membatasi dampak dari dependensi implementasi ketika sebuah program ditulis daripada mencoba menguraikan kekacauan sesudahnya.

Relatif mudah untuk membatasi dampak fitur bahasa tergantung implementasi.

Pertanyaan saya adalah: Bagaimana cara membatasi dampak fitur bahasa tergantung implementasi? Harap sebutkan fitur bahasa tergantung implementasi lalu tunjukkan cara membatasi pengaruhnya.


7
2018-03-09 08:03


asal


Jawaban:


Beberapa ide:

  • Sayangnya Anda harus menggunakan makro untuk menghindari masalah spesifik atau kompiler tertentu platform. Anda dapat melihat header Boost libraries untuk melihat bahwa itu cukup mudah menjadi tidak praktis, misalnya melihat file-file:

  • Jenis integer cenderung berantakan di antara platform yang berbeda, Anda harus mendefinisikan typedef Anda sendiri atau menggunakan sesuatu seperti Dorong cstdint.hpp

  • Jika Anda memutuskan untuk menggunakan pustaka apa pun, lakukan pemeriksaan apakah pustaka tersebut didukung pada platform yang diberikan

  • Gunakan pustaka dengan dukungan yang baik dan dukungan platform yang terdokumentasi dengan jelas (misalnya, Boost)

  • Anda dapat mengabstraksikan diri dari beberapa masalah khusus implementasi C + + dengan sangat bergantung pada pustaka seperti Qt, yang memberikan "alternatif" dalam pengertian jenis dan algoritme. Mereka juga mencoba membuat pengkodean di C ++ lebih portabel. Apakah itu bekerja? Aku tidak yakin.

  • Tidak semuanya bisa dilakukan dengan macro. Sistem build Anda harus dapat mendeteksi platform dan keberadaan pustaka tertentu. Banyak yang akan menyarankan autotools untuk konfigurasi proyek, saya di sisi lain merekomendasikan CMake (bahasa yang agak bagus, tidak lebih M4)

  • endianness dan penyelarasan mungkin menjadi masalah jika Anda melakukan beberapa campur tangan tingkat rendah (yaitu reinterpret_castdan teman-teman hal-hal yang sama (teman adalah kata yang buruk dalam konteks C ++)).

  • melempar banyak bendera peringatan untuk compiler, untuk gcc saya akan merekomendasikan setidaknya -Wall -Wextra. Tetapi masih banyak lagi, lihat dokumentasi dari compiler atau ini pertanyaan.

  • Anda harus berhati-hati terhadap segala sesuatu yang ditentukan oleh implementasi dan dependend-implementasi. Jika Anda menginginkan kebenaran, hanya kebenaran, tidak ada tetapi kebenaran, kemudian pergi ke standar ISO.


4
2018-03-09 08:43



Nah, ukuran variabel yang disebutkan adalah masalah yang cukup dikenal, dengan solusi umum untuk menyediakan versi tipikal dari tipe dasar yang memiliki ukuran yang terdefinisi dengan baik (biasanya diiklankan dalam nama typedef). Ini dilakukan menggunakan makro preprocessor untuk memberikan kode-visibilitas yang berbeda pada platform yang berbeda. Misalnya.:

#ifdef __WIN32__
typedef int int32;
typedef char char8;
//etc
#endif
#ifdef __MACOSX__
//different typedefs to produce same results
#endif

Masalah lain biasanya diselesaikan dengan cara yang sama juga (yaitu menggunakan token preprocessor untuk melakukan kompilasi bersyarat)


4
2018-03-09 08:09



Dependensi implementasi yang paling jelas adalah ukuran tipe integer. Ada banyak cara untuk menangani ini. Cara yang paling jelas adalah menggunakan typedef untuk membuat int dari berbagai ukuran:

 typedef signed   short  int16_t;
 typedef unsigned short  uint16_t;

Triknya di sini adalah memilih konvensi dan menaatinya. Konvensi mana yang merupakan bagian sulit: INT16, int16, int16_t, t_int16, Int16, dll. C99 memiliki file stdint.h yang menggunakan gaya int16_t. Jika kompiler Anda memiliki file ini, gunakanlah.

Demikian pula, Anda harus bertele-tele tentang penggunaan definisi standar lainnya seperti size_t, time_t, dll.

Trik lainnya adalah mengetahui kapan tidak menggunakan typedef ini. Sebuah variabel kontrol loop yang digunakan untuk mengindeks array, seharusnya hanya mengambil tipe raw int sehingga kompilasi akan menghasilkan kode terbaik untuk prosesor Anda. untuk (int32_t i = 0; i <x; ++ i) dapat menghasilkan banyak kode yang tidak diperlukan pada prosesor 64-gigitan, seperti halnya menggunakan int16_t pada prosesor 32-bit.


3
2018-03-09 08:17



Solusi yang baik adalah menggunakan judul-judul yang umum yang mendefinisikan jenis-jenis yang diketik sebagai neccessary.

Misalnya, termasuk sys / types.h adalah cara terbaik untuk mengatasi ini, seperti menggunakan pustaka portabel.


2
2018-03-09 08:15



Ada dua pendekatan untuk ini:

  • tentukan jenis Anda sendiri dengan ukuran yang diketahui dan gunakan mereka alih-alih tipe bawaan (seperti typedef int int32 # if-ed untuk berbagai platform)
  • gunakan teknik yang tidak tergantung pada ukuran jenis

Yang pertama sangat populer, namun yang kedua, bila memungkinkan, biasanya menghasilkan kode yang lebih bersih. Ini termasuk:

  • jangan menganggap pointer dapat dilemparkan ke int
  • jangan berasumsi Anda tahu ukuran byte dari tipe individu, selalu gunakan sizeof untuk memeriksanya
  • saat menyimpan data ke file atau mentransfernya melalui jaringan, gunakan teknik yang portabel di seluruh ukuran data yang berubah (seperti menyimpan / memuat file teks)

Salah satu contoh baru-baru ini adalah menulis kode yang dapat dikompilasi untuk kedua platform x86 dan x64. Bagian yang berbahaya di sini adalah pointer dan size_t size - bersiaplah bisa menjadi 4 atau 8 tergantung pada platform, ketika casting atau pointer differencing, cor tidak pernah ke int, gunakan intptr_t dan jenis typedef-ed yang sejenis.


2
2018-03-09 09:02



Salah satu cara utama untuk menghindari ketergantungan pada ukuran data tertentu adalah membaca & menulis data persisten sebagai teks, bukan biner. Jika data biner harus digunakan maka semua operasi baca / tulis harus dipusatkan dalam beberapa metode dan pendekatan seperti typedef yang sudah dijelaskan di sini digunakan.

Putaran kedua yang dapat Anda lakukan adalah mengaktifkan semua peringatan kompilator Anda. misalnya, menggunakan -bengah Bendera dengan g ++ akan memperingatkan Anda tentang banyak kemungkinan masalah portabilitas.


1
2018-03-09 08:23



Jika Anda khawatir tentang portabilitas, hal-hal seperti ukuran int dapat ditentukan dan ditangani tanpa banyak kesulitan. Banyak kompiler C ++ juga mendukung fitur C99 seperti tipe int: int8_t, uint8_t, int16_t, uint32_t, dll. Jika milik Anda tidak mendukung mereka secara asli, Anda selalu dapat menyertakannya <cstdint> atau <sys/types.h>, yang lebih sering daripada tidak, memilikinya typedefed. <limits.h> memiliki definisi ini untuk semua tipe dasar.

Standar hanya menjamin ukuran minimum tipe, yang selalu dapat Anda andalkan: sizeof(char) < sizeof(short) <= sizeof(int) <= sizeof(long). char minimal harus 8 bit. shortdan int minimal harus 16 bit. long harus setidaknya 32 bit.

Hal-hal lain yang mungkin diterapkan-didefinisikan termasuk skema ABI dan nama-mangling (perilaku export "C++" khusus), tetapi kecuali Anda bekerja dengan lebih dari satu kompilator, itu biasanya tidak masalah.


0
2018-03-09 08:24



Berikut ini juga kutipan dari buku Bjarne Stroustrup, The C ++ Programming Language:

Bagian 10.4.9:

Tidak ada jaminan implementasi-independen yang dibuat tentang urutan konstruksi objek nonlokal dalam unit kompilasi yang berbeda. Sebagai contoh:

// file1.c:
    Table tbl1;
// file2.c:
    Table tbl2;

Apakah tbl1 dibangun sebelumnya tbl2 atau sebaliknya tergantung pada implementasi. Pesanan bahkan tidak dijamin untuk diperbaiki di setiap penerapan tertentu. Dinamis menghubungkan, atau bahkan perubahan kecil dalam proses kompilasi, dapat mengubah urutan. Urutan kerusakan juga tergantung pada implementasi.

Seorang pemrogram dapat memastikan inisialisasi yang tepat dengan mengimplementasikan strategi yang biasanya digunakan oleh implementasi untuk objek statis lokal: saklar pertama kali. Sebagai contoh:

class Zlib {
    static bool initialized;
    static void initialize() { /* initialize */ initialized = true; }
public:
    // no constructor

    void f()
    {
        if (initialized == false) initialize();
        // ...
    }
    // ...
};

Jika ada banyak fungsi yang perlu menguji pergantian pertama kali, ini bisa membosankan, tetapi sering kali dapat dikelola. Teknik ini bergantung pada fakta bahwa benda-benda yang dialokasikan secara statis tanpa konstruktor diinisialisasi 0. Kasus yang benar-benar sulit adalah kasus di mana operasi pertama dapat menjadi sangat penting sehingga biaya pengujian dan kemungkinan inisialisasi dapat menjadi serius. Dalam hal ini, tipuan lebih lanjut diperlukan (§21.5.2).

Pendekatan alternatif untuk objek sederhana adalah menyajikannya sebagai fungsi (§9.4.1):

int& obj() { static int x = 0; return x; } // initialized upon first use

Sakelar pertama kali tidak menangani setiap situasi yang memungkinkan. Misalnya, dimungkinkan untuk membuat objek yang merujuk satu sama lain selama konstruksi. Contoh-contoh semacam itu sebaiknya dihindari. Jika benda-benda tersebut diperlukan, mereka harus dibangun secara hati-hati secara bertahap.


0
2017-09-19 15:38