Pendekatan modular pada umumnya cukup praktis (portabel dan bersih), jadi saya mencoba memprogram modul yang terpisah dari modul lainnya. Sebagian besar pendekatan saya didasarkan pada sebuah struct yang menggambarkan modul itu sendiri. Fungsi inisialisasi menetapkan parameter utama, kemudian pawang (pointer ke struct deskriptif) dilewatkan ke fungsi apa pun di dalam modul yang disebut.
Saat ini, saya bertanya-tanya apa pendekatan terbaik alokasi memori untuk struct yang menggambarkan modul. Jika memungkinkan, saya ingin yang berikut ini:
- Struct buram, sehingga struct hanya dapat diubah oleh penggunaan fungsi antarmuka yang disediakan
- Banyak contoh
- memori yang dialokasikan oleh tautan
Saya melihat kemungkinan berikut, bahwa semua bertentangan dengan salah satu tujuan saya:
deklarasi global
banyak contoh, dialihkan oleh tautan, tetapi struct tidak buram
(#includes)
module_struct module;
void main(){
module_init(&module);
}
malloc
struct buram, beberapa contoh, tetapi semua ramuan di tumpukan
dalam module.h:
typedef module_struct Module;
dalam fungsi module.c init, malloc dan mengembalikan pointer ke memori yang dialokasikan
module_mem = malloc(sizeof(module_struct ));
/* initialize values here */
return module_mem;
di main.c
(#includes)
Module *module;
void main(){
module = module_init();
}
deklarasi dalam modul
struct buram, dialokasikan oleh linker, hanya jumlah instance yang telah ditentukan
menjaga seluruh struct dan memori internal ke modul dan tidak pernah mengekspos handler atau struct.
(#includes)
void main(){
module_init(_no_param_or_index_if_multiple_instances_possible_);
}
Apakah ada opsi untuk menggabungkan ini entah bagaimana untuk struct buram, linker alih-alih alokasi tumpukan dan beberapa / jumlah instance?
larutan
seperti yang diusulkan dalam beberapa jawaban di bawah ini, saya pikir cara terbaik adalah:
- cadangan ruang untuk MODULE_MAX_INSTANCE_COUNT modul dalam file sumber modul
- jangan mendefinisikan MODULE_MAX_INSTANCE_COUNT dalam modul itu sendiri
- tambahkan #ifndef MODULE_MAX_INSTANCE_COUNT #error ke file header modul untuk memastikan pengguna modul mengetahui batasan ini dan menentukan jumlah instance maksimum yang diinginkan untuk aplikasi
- pada inisialisasi instance, kembalikan alamat memori (* void) dari struct desricptive atau indeks modul (apa pun yang Anda suka)
Jawaban:
Tentu ada. Namun, pertama-tama, ketahuilah bahwa "jumlah apa pun" instance harus diperbaiki, atau setidaknya batas atas yang ditetapkan, pada waktu kompilasi. Ini merupakan prasyarat agar instance dialokasikan secara statis (apa yang Anda sebut "alokasi tautan"). Anda dapat membuat angka dapat disesuaikan tanpa modifikasi sumber dengan mendeklarasikan makro yang menentukannya.
Kemudian file sumber yang berisi deklarasi struct aktual dan semua fungsi yang terkait juga mendeklarasikan array instance dengan tautan internal. Ini menyediakan array, dengan tautan eksternal, dari pointer ke instance atau fungsi untuk mengakses berbagai pointer berdasarkan indeks. Variasi fungsi sedikit lebih modular:
module.c
Saya kira Anda sudah terbiasa dengan bagaimana header akan mendeklarasikan struct sebagai tipe yang tidak lengkap dan mendeklarasikan semua fungsi (ditulis dalam bentuk pointer ke tipe itu). Sebagai contoh:
module.h
Sekarang
struct module
opak di unit terjemahan selainmodule.c
, * dan Anda dapat mengakses dan menggunakan hingga jumlah instance yang ditentukan pada waktu kompilasi tanpa alokasi dinamis apa pun.* Kecuali Anda menyalin definisinya, tentu saja. Intinya adalah
module.h
jangan lakukan itu.sumber
Saya memprogram pengendali mikro kecil di C ++, yang mencapai apa yang Anda inginkan.
Apa yang Anda sebut modul adalah kelas C ++, ia dapat berisi data (baik yang dapat diakses secara eksternal atau tidak) dan fungsinya (juga). Konstruktor (fungsi khusus) memulai itu. Konstruktor dapat mengambil parameter run-time atau (waktu tempuh) parameter (favorit saya) saya. Fungsi-fungsi dalam kelas secara implisit mendapatkan variabel kelas sebagai parameter pertama. (Atau, seringkali preferensi saya, kelas dapat bertindak sebagai singleton tersembunyi, sehingga semua data diakses tanpa overhead ini).
Objek kelas dapat bersifat global (sehingga Anda tahu pada saat tautan bahwa semuanya akan cocok), atau stack-local, mungkin di main. (Saya tidak suka C ++ global karena urutan inisialisasi global yang tidak ditentukan, jadi saya lebih suka stack-lokal).
Gaya pemrograman pilihan saya adalah bahwa modul adalah kelas statis, dan konfigurasi (statis) mereka adalah dengan parameter template. Ini menghindari hampir semua overhad dan memungkinkan optimasi. Kombinasikan ini dengan alat yang menghitung ukuran tumpukan dan Anda dapat tidur tanpa khawatir :)
Pembicaraan saya tentang cara pengkodean dalam C ++: Objects? Tidak, terima kasih!
Banyak programmer embedded / mikrokontroler tampaknya tidak menyukai C ++ karena mereka pikir itu akan memaksa mereka untuk menggunakan semua C ++. Itu sama sekali tidak perlu, dan akan menjadi ide yang sangat buruk. (Anda mungkin juga tidak menggunakan semua C! Pikirkan heap, floating point, setjmp / longjmp, printf, ...)
Dalam komentarnya Adam Haun menyebutkan RAII dan inisialisasi. IMO RAII lebih terkait dengan dekonstruksi, tetapi poinnya valid: objek global akan dibangun sebelum mulai utama Anda, sehingga mereka dapat bekerja pada asumsi yang tidak valid (seperti kecepatan clock utama yang akan diubah nanti). Itu adalah satu lagi alasan untuk TIDAK menggunakan objek yang diinisialisasi kode global. (Saya menggunakan skrip linker yang akan gagal ketika saya memiliki objek yang diinisialisasi kode global.) IMO 'objek' tersebut harus dibuat dan diteruskan secara eksplisit. Ini termasuk objek 'fasilitas menunggu' 'yang menyediakan fungsi wait (). Dalam pengaturan saya ini adalah 'objek' yang mengatur kecepatan clock chip.
Berbicara tentang RAII: itu adalah satu lagi fitur C ++ yang sangat berguna dalam sistem embedded kecil, meskipun bukan karena alasan (memory deallocation) yang paling banyak digunakan dalam sistem largere (sistem embedded kecil kebanyakan tidak menggunakan deallocation memory dinamis). Pikirkan untuk mengunci sumber daya: Anda dapat menjadikan sumber daya yang dikunci sebagai objek pembungkus, dan membatasi akses ke sumber daya hanya dimungkinkan melalui bungkus pengunci. Ketika pembungkus keluar dari ruang lingkup, sumber daya tidak dikunci. Ini mencegah akses tanpa mengunci, dan membuatnya lebih tidak mungkin untuk melupakan pembukaan kunci. dengan beberapa sihir (templat) itu bisa nol di atas kepala.
Pertanyaan aslinya tidak menyebutkan C, maka jawaban C ++ - centric saya. Jika benar-benar harus ....
Anda dapat menggunakan tipuan makro: nyatakan stucts Anda secara publik, sehingga mereka memiliki tipe dan dapat dialokasikan secara global, tetapi potong nama-nama komponen mereka di luar kegunaan, kecuali beberapa makro didefinisikan secara berbeda, yang merupakan kasus dalam file .c modul Anda. Untuk keamanan ekstra, Anda dapat menggunakan waktu kompilasi dalam mangling.
Atau miliki versi publik dari struct Anda yang tidak memiliki apa pun yang berguna di dalamnya, dan miliki versi pribadi (dengan data yang berguna) hanya di file .c Anda, dan nyatakan bahwa ukurannya sama. Sedikit tipuan file make bisa mengotomatiskan ini.
@Lundins berkomentar tentang programmer yang buruk (tertanam):
Jenis programmer yang Anda gambarkan mungkin akan membuat kekacauan dalam bahasa apa pun. Makro (hadir dalam C dan C ++) adalah salah satu cara yang jelas.
Tooling dapat membantu sampai batas tertentu. Untuk murid-murid saya, saya memberi mandat skrip dibangun yang menentukan tanpa-pengecualian, tidak-rtti, dan memberikan kesalahan linker ketika tumpukan digunakan atau global-inisialisasi kode hadir. Dan itu menentukan peringatan = kesalahan dan mengaktifkan hampir semua peringatan.
Saya menganjurkan menggunakan templat, tetapi dengan constappr dan konsep metaprogramming semakin dibutuhkan.
"programmer Arduino yang bingung" Saya sangat ingin mengganti gaya pemrograman Arduino (kabel, replikasi kode di perpustakaan) dengan pendekatan C ++ modern, yang dapat lebih mudah, lebih aman, dan menghasilkan kode yang lebih cepat dan lebih kecil. Kalau saja saya punya waktu dan kekuatan ....
sumber
Saya percaya FreeRTOS (mungkin OS lain?) Melakukan sesuatu seperti apa yang Anda cari dengan mendefinisikan 2 versi berbeda dari struct.
Yang 'asli', digunakan secara internal oleh fungsi OS, dan yang 'palsu' yang ukurannya sama dengan yang 'asli', tetapi tidak memiliki anggota yang berguna di dalamnya (hanya sekelompok
int dummy1
dan sejenisnya).Hanya struct 'palsu' yang diekspos di luar kode OS, dan ini digunakan untuk mengalokasikan memori ke instance statis dari struct.
Secara internal, ketika fungsi-fungsi dalam OS dipanggil, mereka meneruskan alamat struct 'palsu' eksternal sebagai pegangan, dan ini kemudian typecast sebagai pointer ke struct 'nyata' sehingga fungsi-fungsi OS dapat melakukan apa yang mereka butuhkan untuk melakukan.
sumber
Menurut saya, ini tidak ada gunanya. Anda dapat memberikan komentar di sana, tetapi tidak ada gunanya mencoba menyembunyikannya lebih lanjut.
C tidak akan pernah memberikan isolasi setinggi itu, bahkan jika tidak ada deklarasi untuk struct, akan mudah untuk secara tidak sengaja menimpanya dengan mis miscancake memcpy () atau buffer overflow.
Sebagai gantinya, beri saja struct nama dan percaya orang lain untuk menulis kode yang baik juga. Ini juga akan membuat proses debug lebih mudah ketika struct memiliki nama yang dapat Anda gunakan untuk merujuknya.
sumber
Pertanyaan SW murni lebih baik ditanyakan di /programming/ .
Konsep dengan mengekspos sebuah struct tipe tidak lengkap untuk penelepon, seperti yang Anda jelaskan, sering disebut "tipe buram" atau "pointer buram" - struct anonim berarti sesuatu yang sama sekali berbeda.
Masalah dengan ini adalah bahwa penelepon tidak akan dapat mengalokasikan instance objek, hanya pointer ke sana. Pada PC Anda akan menggunakan
malloc
di dalam objek "konstruktor", tetapi malloc adalah no-go dalam sistem embedded.Jadi apa yang Anda lakukan di embedded adalah menyediakan kumpulan memori. Anda memiliki jumlah RAM yang terbatas, sehingga membatasi jumlah objek yang dapat dibuat biasanya tidak menjadi masalah.
Lihat alokasi statis tipe data buram ke arah di SO.
sumber