Apakah ada pedoman yang diterima secara umum tentang bagaimana menulis C modern?


13

Saya memiliki latar belakang Java / Groovy yang kuat dan saya telah ditugaskan ke tim yang memelihara basis kode C yang cukup besar untuk perangkat lunak administratif.

Beberapa titik sakit, seperti berurusan dengan gumpalan di database atau menghasilkan laporan dalam PDF dan Excel telah dieksternalisasi ke layanan web java.

Namun, sebagai seorang pengembang Java, saya agak bingung dengan beberapa aspek kode:

  • itu verbose (terutama ketika berhadapan dengan 'pengecualian')
  • ada banyak metode besar (banyak 2000 + metode baris)
  • tidak ada struktur data lanjutan (Saya sangat merindukan Daftar, Mengatur dan Memetakan)
  • tidak ada pemisahan perhatian (SQL dicampur dengan gembira di sekitar kode)

Akibatnya saya merasa bahwa bisnis ini tersembunyi dalam banyak kode teknis dan otak saya, dibentuk dengan Object Oriented dan sejumput pemrograman Fungsional, tidak nyaman.

Sisi baik dari proyek ini adalah bahwa kode lurus ke depan: tidak ada kerangka kerja, tidak ada manipulasi kode byte saat runtime, tidak ada AOP. Dan server dapat secara bersamaan menjawab 10.000 pengguna dengan satu mesin dengan menggunakan lebih sedikit memori daripada kebutuhan java untuk meludah "hello world".

Saya ingin belajar bagaimana menulis kode C sesuai dengan prinsip-prinsip modern yang diterima secara umum. Apakah ada prinsip yang diterima secara umum tentang bagaimana C modern harus ditulis dan disusun?

Sesuatu yang mirip dengan buku 'Java Efektif', tetapi untuk C.

Edit berdasarkan jawaban dan komentar:

  • Saya akan mencoba untuk menyesuaikan pola pikir saya ke kode C dan tidak mencoba untuk mencerminkannya ke OOP.
  • Saya sudah mulai memindai-membaca panduan gaya pengkodean yang direkomendasikan dari komentar (Standar Pengkodean GNU dan Gaya Pengodean Kernel Linux).
  • Saya kemudian akan mencoba mengusulkan gaya kode ini kepada rekan kerja saya. Bagian yang paling sulit adalah meyakinkan rekan kerja bahwa metode besar dapat dibagi menjadi bagian-bagian yang lebih kecil dan bahwa mengulangi 4 baris kode penanganan kesalahan yang sama dapat dihindari dengan bantuan metode.

5
Apakah aplikasi tersebut benar-benar perlu dimodernisasi, atau apakah Anda hanya berpikir itu melakukannya karena cara itu ditulis tidak dikenal?
Blrfl


1
@ Blrfl, saya merasa bahwa aplikasi telah ditulis dengan standar yang sudah ketinggalan zaman. Saya hanya ingin tahu apa yang hari ini (2016) standar untuk (administrasi) C. Jika ada satu. Saya tidak ingin memperbaiki atau membentuk kembali aplikasi saat ini, saya ingin tahu bagaimana saya harus menulis bagian selanjutnya dari kode.
Guillaume


3
@antlersoft: Fungsi 2.000 baris yang melakukan daftar panjang hal-hal sederhana, satu demi satu, sama sekali tidak ada masalah dan tidak perlu alasan. Tolong jangan balas dengan argumen melingkar seperti "Anda seharusnya tidak menulis 2.000 fungsi garis karena Anda seharusnya tidak menulis 2.000 fungsi garis".
gnasher729

Jawaban:


14

Saya dapat membaca dari pertanyaan Anda masalahnya bukan bahwa kode itu adalah C lama tetapi hanya pemrograman yang buruk . Sebagian besar masalah yang Anda sebutkan seperti verbositas, fungsi garis 2000+ besar, atau tidak ada pemisahan kekhawatiran berlaku untuk bahasa apa pun, C atau Java sama.

Verbositas disebutkan dalam konteks penanganan kesalahan. Anda tidak memberikan contoh jadi saya hanya dapat mengingatkan bahwa kode penanganan kesalahan juga merupakan kode . Tidak ada alasan untuk bagian berulang kode boilerplate. Faktorkan itu; baik ke fungsi atau (jika itu tidak layak untuk membuat fungsi terpisah) lakukan goto Error;pola dan pindahkan penanganan kesalahan dan pembersihan sumber daya ke Error:bagian di bagian bawah fungsi.

Jika melewatkan kesalahan pada rantai panggilan tampaknya menjadi masalah, tanyakan pada diri sendiri: apakah fungsi di sana benar - benar perlu tahu beberapa pria kecil di sini punya masalah? Mekanisme pengecualian bawaan dalam bahasa membuatnya mudah untuk dilakukan, tetapi secara umum lebih baik untuk menangani pengecualian lebih awal (dalam bahasa apa pun) sehingga kondisi kesalahan tidak mencemari logika kode tingkat tinggi. Dan jika fungsi di sana benar-benar perlu diketahui, ada cara untuk meniru pengecualian dengan setjmpdan longjmp.

Saya pikir satu-satunya masalah terkait C yang disebutkan adalah kurangnya wadah standar. Meskipun Setsecara umum dapat diganti dengan array yang diurutkan dan Map(sebagian besar) dengan array berpasangan atau struct(jika Anda tahu set kunci sebelumnya, map[key] = valueberubah menjadi s.key = value), tetapi kenyataannya tidak ada wadah array dinamis dalam standar. Perpustakaan. Dalam C99 Anda setidaknya dapat mendeklarasikan array panjang variabel pada stack ( int array[len]) tetapi Anda harus menghitung lensebelumnya (biasanya tidak sulit) dan tentu saja Anda tidak dapat mengembalikannya sebagai objek stack-dialokasikan. Sebagian besar proyek berakhir dengan menulis wadah array dinamis mereka sendiri atau mengadopsi yang open-source.

Pada catatan penutup, saya ingin menunjukkan bahwa saya pernah ke sana. Saya telah menjadi programmer Java yang pindah ke C ++ dan pure C. Saya ingin menyarankan "baca buku X untuk belajar C yang baik" tetapi tidak ada sama seperti tidak ada untuk Java. Cara untuk maju adalah dengan menyerap semua kerumitan bahasa dan perpustakaan standar; google banyak, banyak membaca, dan banyak kode sampai Anda mulai berpikir dalam C. Mencoba untuk menulis hal-hal dalam C seperti yang Anda lakukan di Jawa sama frustasinya dengan mencoba menulis kalimat dalam bahasa asing dengan kata-kata yang langsung diterjemahkan dari ibu Anda lidah; Anda dan pembaca akan merasa ngeri. Kabar baiknya adalah bahwa belajar pemrograman yang baik lambat tetapi belajar bahasa lain cepat. jadi jika Anda menulis kode yang layak di Jawa,


1
Secara keseluruhan, ini adalah jawaban yang sangat bagus. Saya hanya akan keberatan melihat setjmp()/ longjmp()sebagai alat yang valid: Ia bahkan tidak mencoba melakukan pembersihan. Alokasi apa pun akan dibocorkan, kunci yang ditahan tidak akan dirilis, file apa pun yang dibuka tidak akan ditutup, dan setiap inkonsistensi data sementara akan menjadi permanen. IMHO, pasangan fungsi ini pada dasarnya adalah retasan terburuk yang pernah ditemukan, dengan satu-satunya justifikasi bahwa itu mungkin untuk diterapkan. Pada akhirnya, hanya ada satu cara yang valid untuk melakukan penanganan kesalahan di C: kode kesalahan eksplisit.
cmaster - mengembalikan monica

@ cmaster ya. Secara pribadi, setjmp/longjmptampak ikan keluar dari air di C dan saya tidak pernah menggunakannya. Saya merasa harus memasukkannya hanya karena banyaknya tutorial / perpustakaan di internet untuk meniru pengecualian, jadi saya pikir ada orang di luar yang benar-benar menggunakannya.
An Owl

7

Sisi baik dari proyek ini adalah bahwa kode lurus ke depan: tidak ada kerangka kerja, tidak ada manipulasi kode byte saat runtime, tidak ada AOP. Dan server dapat secara bersamaan menjawab 10.000 pengguna dengan satu mesin dengan menggunakan lebih sedikit memori daripada kebutuhan java untuk meludah "hello world".

Saya akan merekomendasikan Anda berhati-hati apakah ini sepadan dengan waktu Anda dan uang perusahaan untuk menghabiskan sumber daya pada "memodernisasi" perangkat lunak yang berfungsi dengan kompleksitas kode rendah dan yang berkinerja baik. Ada tudung besar yang memungkinkan Anda memperkenalkan bug baru sendiri, terutama karena tampaknya ini adalah sistem yang tidak Anda kenal.

Jika Anda masih ingin turun rute itu maka saya akan menyarankan yang berikut:

  • Buat (atau hasilkan) diagram status perangkat lunak / kode tersebut
  • Selami kode tersebut dan buatlah daftar bagian yang paling kompleks atau paling kritis dari masing-masing kode
  • Temukan seseorang yang memiliki pengetahuan tentang basis kode itu dan tanyakan kepada mereka mengapa itu dibuat dengan cara ini dan apa yang diketahui menyebabkan masalah
  • Tulis dokumentasi dari apa yang telah Anda pelajari

Pada titik ini, Anda akan memutuskan apakah ini pantas ditelusuri atau tidak. Jika budaya perusahaan Anda tidak menghargai kegagalan maka dapatkan lampu hijau dari atasan atau manajer.

  • Buat kompartemen berbagai blok bangunan perangkat lunak dan tulis unit test untuk masing-masingnya.
  • Iterasi sampai Anda dapat menempelkan berbagai modul yang berbeda
  • Lakukan pengujian lebih lanjut yang mensimulasikan interaksi pengguna nyata (stress test dll.)

Saya pikir itu peta jalan yang cukup bagus dan membawa Anda ke mana pun Anda butuhkan. Tanpa mengetahui spesifik dari proyek ini sulit untuk banyak membantu Anda. Tolong jangan membuang penafian saya sebagai terlalu mengkhawatirkan. Banyak programmer yang hebat telah mengalahkan debu dengan mencoba menulis ulang proyek yang ada ke bahasa favorit mereka atau menggunakan alat "modern". Itu keputusan yang harus dipikirkan dengan hati-hati dan saya mendorong Anda untuk tidak nakal dan melakukannya sendiri tanpa dukungan manajemen atau bantuan dari kolega Anda.


2
Saya menyadari bahwa pertanyaan saya sama sekali tidak jelas. Saya tidak ingin memperbaiki kode. Sama sekali. Saya ingin mempertahankan basis kode yang ada sebagaimana adanya. Namun saya ingin belajar cara menulis C modern untuk fitur baru. Dan di sini saya tersesat. Sebagian besar dokumentasi yang saya temukan adalah tentang cara membuat kode dalam C, bukan tentang cara menulis 'modern' C. Mungkin tidak ada yang namanya 'modern' C ...
Guillaume

1

Jika Anda lebih suka bahasa tingkat yang lebih tinggi, ada beberapa bahasa seperti C ++ atau Objective-C yang dapat dicampur dengan kode C dengan cukup mudah.

Atau, C dan C ++ cukup kompatibel. Anda mungkin bisa mengkompilasi seluruh basis kode sebagai C ++ dengan sedikit perubahan - Anda akan memiliki variabel sesekali bernama "kelas" atau "templat" yang perlu Anda ganti namanya, tetapi dalam praktiknya itu saja. (sizeof ('a') berbeda dalam C dan C ++, tapi saya rasa saya tidak pernah menggunakannya).

Jika Anda memilih rute itu, pertimbangkan bahwa pengelola berikutnya mungkin tidak terlalu lancar menggunakan C ++. Jangan terbawa suasana. Manfaatkan C ++, tetapi hanya sejauh ini seorang programmer C dapat dengan mudah memahaminya.


1
Saya harus tidak setuju di sini. C dan C ++ adalah bahasa yang berbeda, dan beberapa kode yang diperlukan oleh kompiler C ++ (secara eksplisit casting nilai pengembalian malloc) dianggap praktik buruk di C. Arti dari constdan inlinejuga sangat berbeda antara C dan C ++, dan tentu saja C ++ tidak mengerti __restrict. Jangan memperlakukan bahasa sebagai yang dapat dipertukarkan, bahkan dalam subset sumber yang dikompilasi dalam keduanya.
Angew tidak lagi bangga pada

1

Pada dasarnya, menulis kode C yang baik sama seperti menulis kode C ++ atau Java yang baik: Anda ingin kelas, gunakan a struct. Anda ingin warisan, sertakan basis structsebagai anggota pertama tanpa nama. Anda ingin fungsi virtual, tambahkan pointer ke pointer structfungsi statis . Dan seterusnya, dll. Ini persis apa yang dilakukan C ++ di bawah tenda, satu-satunya perbedaan adalah, bahwa itu eksplisit dalam C. Dengan demikian, Anda dapat melakukan pemrograman berorientasi objek dengan sempurna di C, itu hanya terlihat sedikit berbeda dan lebih sederhana daripada apa yang Anda digunakan untuk.

Intinya, pemrograman yang baik itu tentang paradigma, bukan tentang fitur bahasa. Benar, itu selalu baik jika fitur bahasa Anda memberikan dukungan yang baik untuk paradigma yang ingin Anda gunakan, tetapi fitur bahasa bukan keharusan. Setelah Anda menyadarinya, Anda dapat menulis kode yang bagus dalam hampir semua bahasa (terlepas dari beberapa bahasa esoterik seperti Brainfuck atau INTERCAL, yaitu).

Tentu saja, masalahnya tetap bahwa pustaka C standar tidak berisi salah satu dari kelas wadah bagus yang Anda gunakan. Sayangnya, itu berarti Anda harus menggunakan milik Anda sendiri, atau mengatasi kekurangan ini dengan menggunakan array yang dialokasikan secara dinamis. Tetapi saya berani bertaruh Anda akan segera mengetahui, bahwa yang Anda perlukan adalah array dinamis ( malloc()) dan daftar / pohon tertaut yang diimplementasikan melalui anggota pointer di dalam kelas Anda.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.