Satu hal yang secara intuitif selalu mengejutkan saya sebagai fitur positif C (well, sebenarnya implementasinya seperti gcc, clang, ...) adalah kenyataan bahwa ia tidak menyimpan informasi tersembunyi apa pun di sebelah variabel Anda sendiri saat runtime. Maksud saya, jika Anda misalnya menginginkan variabel "x" dari jenis "uint16_t", Anda dapat yakin bahwa "x" hanya akan menempati 2 byte ruang (dan tidak akan membawa informasi tersembunyi seperti jenisnya dll. .). Demikian pula, jika Anda menginginkan array 100 bilangan bulat, Anda bisa yakin itu sebesar 100 bilangan bulat.
Namun, semakin saya mencoba untuk datang dengan kasus penggunaan beton untuk fitur ini semakin saya bertanya-tanya apakah itu benar-benar memiliki setiap keuntungan praktis sama sekali. Satu-satunya hal yang saya dapat sampai sejauh ini adalah bahwa itu jelas membutuhkan lebih sedikit RAM. Untuk lingkungan terbatas, seperti chip AVR dll., Ini jelas merupakan nilai tambah yang besar, tetapi untuk kasus penggunaan desktop / server sehari-hari, tampaknya agak tidak relevan. Kemungkinan lain yang saya pikirkan adalah mungkin bermanfaat / penting untuk mengakses perangkat keras, atau mungkin memetakan wilayah memori (misalnya untuk output VGA dan sejenisnya) ...?
Pertanyaan saya: Apakah ada domain konkret yang tidak dapat atau hanya dapat diimplementasikan dengan sangat rumit tanpa fitur ini?
PS Tolong beritahu saya jika Anda memiliki nama yang lebih baik untuk itu! ;)
sumber
virtual
fungsi anggota. Jadi RTTI tidak pernah meningkatkan ukuran benda apa pun, itu hanya membuat biner lebih besar dengan konstanta.T *
selalu berukuran sama danT
mungkin berisi bidang tersembunyi yang menunjuk ke vtable. Dan tidak ada kompiler C ++ yang pernah memasukkan vtables ke objek yang tidak membutuhkannya.Jawaban:
Ada beberapa manfaat, yang jelas adalah pada waktu kompilasi untuk memastikan bahwa hal-hal seperti parameter fungsi cocok dengan nilai yang diteruskan.
Tapi saya pikir Anda bertanya tentang apa yang terjadi pada saat runtime.
Perlu diingat bahwa kompiler akan membuat runtime yang menanamkan pengetahuan tentang tipe data dalam operasi yang dilakukannya. Setiap potongan data dalam memori mungkin tidak menggambarkan diri, tetapi kode secara inheren tahu apa data itu (jika Anda telah melakukan pekerjaan Anda dengan benar).
Saat runtime hal-hal sedikit berbeda dari yang Anda pikirkan.
Misalnya, jangan berasumsi bahwa hanya dua byte yang digunakan ketika Anda mendeklarasikan uint16_t. Tergantung pada prosesor dan penyelarasan kata itu dapat menempati 16, 32 atau 64 bit pada tumpukan. Anda mungkin menemukan bahwa array celana pendek Anda mengkonsumsi lebih banyak memori daripada yang Anda harapkan.
Ini bisa menjadi masalah dalam situasi tertentu di mana Anda perlu referensi data pada offset tertentu. Ini terjadi ketika berkomunikasi antara dua sistem yang memiliki arsitektur prosesor yang berbeda, baik melalui tautan nirkabel, atau melalui file.
C memungkinkan Anda untuk menentukan struct dengan granularity level bit:
Struktur ini panjangnya tiga byte, dengan pendek didefinisikan untuk memulai pada offset aneh. Ini juga perlu dikemas agar persis seperti yang Anda definisikan. Kalau tidak, kompiler akan menyelaraskan kata para anggota.
Kompiler akan menghasilkan kode di belakang layar untuk mengekstrak data ini dan menyalinnya ke dalam register sehingga Anda dapat melakukan hal-hal yang bermanfaat dengannya.
Sekarang Anda dapat melihat bahwa setiap kali program saya mengakses anggota dari myMessage struct, ia akan tahu bagaimana tepatnya mengekstraksi dan mengoperasikannya.
Ini bisa menjadi masalah dan sulit untuk dikelola ketika berkomunikasi antara sistem yang berbeda dengan versi perangkat lunak yang berbeda. Anda harus hati-hati merancang sistem & kode untuk memastikan kedua belah pihak memiliki definisi yang sama persis dari tipe data. Ini bisa sangat menantang di beberapa lingkungan. Di sinilah Anda memerlukan protokol yang lebih baik yang berisi data uraian sendiri seperti Google's Protocol Buffer .
Terakhir, Anda membuat poin yang bagus untuk menanyakan seberapa penting hal ini di lingkungan desktop / server. Ini benar-benar tergantung pada berapa banyak memori yang Anda rencanakan untuk digunakan. Jika Anda melakukan sesuatu seperti pemrosesan gambar, Anda mungkin akan menggunakan memori dalam jumlah besar yang dapat mempengaruhi kinerja aplikasi Anda. Ini pasti selalu menjadi perhatian di lingkungan tertanam di mana memori dibatasi dan tidak ada memori virtual.
sumber
short
. Tetapi ini adalah persyaratan satu kali untuk memulai array, sisanya secara otomatis disejajarkan berdasarkan berturut-turut.uint8_t padding: 6;
, seperti dua bit pertama. Atau, lebih jelas, hanya komentar//6 bits of padding inserted by the compiler
. Struktur, seperti yang Anda tulis, memiliki ukuran setidaknya sembilan byte, bukan tiga.Anda menekan satu-satunya alasan ini berguna: memetakan struktur data eksternal. Itu termasuk buffer video yang dipetakan memori, register perangkat keras, dll. Mereka juga memasukkan data yang ditransmisikan secara utuh di luar program, seperti sertifikat SSL, paket IP, gambar JPEG, dan hampir semua struktur data lain yang memiliki umur yang bertahan di luar program.
sumber
C adalah bahasa tingkat rendah, hampir merupakan perakit portabel, sehingga struktur data dan konstruk bahasanya mendekati logam (struktur data tidak memiliki biaya tersembunyi - kecuali batasan bantalan, pelurusan dan ukuran yang dikenakan oleh perangkat keras dan ABI ). Jadi C memang tidak memiliki pengetikan dinamis secara asli. Tetapi jika Anda membutuhkannya, Anda dapat mengadopsi konvensi bahwa semua nilai Anda adalah agregat yang dimulai dengan beberapa jenis informasi (misalnya beberapa
enum
...); useunion
-s dan (untuk array-like things) anggota array fleksibel dalamstruct
memuat juga ukuran array.(saat memprogram dalam C, Anda bertanggung jawab untuk mendefinisikan, mendokumentasikan, dan mengikuti konvensi yang bermanfaat - terutama pra dan pasca kondisi dan invarian; juga alokasi memori dinamis C memerlukan konvensi penjelasan tentang siapa yang harus memiliki
free
beberapamalloc
zona memori yang ditumpuk )Jadi, untuk merepresentasikan nilai-nilai yang merupakan bilangan bulat kotak, atau string, atau semacam simbol seperti Skema , atau vektor nilai, Anda akan secara konseptual menggunakan gabungan tag (diimplementasikan sebagai gabungan pointer) -selalu dimulai dengan jenis ketik -, misalnya:
Untuk mendapatkan tipe nilai yang dinamis
Berikut ini adalah "pemeran dinamis" untuk vektor:
dan vektor "safe accessor" di dalam:
Anda biasanya akan mendefinisikan sebagian besar fungsi pendek di atas seperti
static inline
pada beberapa file header.BTW, jika Anda dapat menggunakan pengumpul sampah Boehm, Anda kemudian dapat membuat kode dengan mudah dalam gaya tingkat tinggi (tetapi tidak aman), dan beberapa juru bahasa Skema melakukannya dengan cara itu. Konstruktor vektor variadik bisa jadi
dan jika Anda memiliki tiga variabel
Anda dapat membangun vektor dari mereka menggunakan
make_vector(3,v1,v2,v3)
Jika Anda tidak ingin menggunakan pengumpul sampah Boehm (atau mendesain sendiri milik Anda), Anda harus sangat berhati-hati dalam mendefinisikan destruktor dan mendokumentasikan siapa, bagaimana, dan kapan memori harus
free
-d; lihat contoh ini . Jadi Anda bisa menggunakanmalloc
(tapi kemudian menguji kegagalannya) alih-alih diGC_MALLOC
atas tetapi Anda perlu mendefinisikan dan menggunakan beberapa fungsi destruktor dengan hati-hativoid destroy_value(value_t)
Kekuatan C adalah level yang cukup rendah untuk membuat kode seperti di atas menjadi mungkin dan mendefinisikan konvensi Anda sendiri (khusus untuk perangkat lunak Anda).
sumber