Modern C'nin nasıl yazılacağı konusunda yaygın olarak kabul gören herhangi bir kılavuz var mı?


13

Güçlü bir Java / Groovy geçmişim var ve bir yönetim yazılımı için oldukça büyük bir C kodu tabanı tutan bir ekibe atandım.

Veritabanındaki blob ile uğraşmak veya PDF ve Excel'de raporlar oluşturmak gibi bazı acı noktaları java web hizmetine dışsallaştırılmıştır.

Ancak, bir Java dev olarak, kodun bazı yönleri ile biraz kafam karıştı:

  • ayrıntılı (özellikle 'istisna' ile uğraşırken)
  • çok büyük yöntemler var (birçok 2000+ satır yöntemi)
  • Gelişmiş veri yapıları yoktur (Liste, Set ve Harita'yı çok özlüyorum)
  • endişe ayrımı yok (SQL tüm kod etrafında sevinçle karıştırılır)

Sonuç olarak, işin tonlarca teknik kodda gizlendiğini ve Nesneye Yönelik ve bir tutam Fonksiyonel programlama ile şekillendirilmiş beynimin rahat olmadığını hissediyorum.

Projenin iyi tarafı, kodun düz olmasıdır: çerçeve yok, çalışma zamanında bayt kodu manipülasyonu yok, AOP yok. Ve sunucu aynı anda java "merhaba dünya" tükürmek için gerekenden daha az bellek kullanarak tek bir makine ile 10000 + kullanıcılara cevap verebilir.

Yaygın olarak kabul gören modern ilkelere göre C kodunun nasıl yazılacağını öğrenmek istiyorum. Modern C'nin nasıl yazılması ve yapılandırılması gerektiği konusunda yaygın kabul gören ilkeler var mı?

'Etkili Java' kitabının eşdeğeri gibi bir şey, ancak C için.

Cevaplar ve yorumlar ışığında düzenleyin:

  • Zihniyetimi C koduna uyarlamaya çalışacağım ve OOP'ye yansıtmaya çalışmayacağım.
  • Yorumdan önerilen kodlama stili kılavuzlarını taramaya başladım (GNU Kodlama Standartları ve Linux Çekirdek Kodlama Stili).
  • Daha sonra bu kod stilini iş arkadaşlarıma önereceğim. İşin en zor yanı, iş arkadaşlarını büyük yöntemin daha küçük parçalara bölünebileceğine ve aynı 4 satır hata işleme kodunu tekrarlamanın bir yöntem yardımıyla önlenebileceğine ikna etmek olabilir.

5
Uygulamanın gerçekten modernleştirilmesi gerekiyor mu, yoksa sadece yazılma şekli tanıdık olmadığından mı düşünüyorsunuz?
Blrfl


1
@Blrfl, uygulamanın eski standartlarla yazılmış olduğunu hissediyorum. Sadece (idari) C için bugün (2016) standart olanı bilmek istiyorum. Mevcut uygulamayı yeniden şekillendirmek veya yeniden şekillendirmek istemiyorum, kodun bir sonraki bölümünü nasıl yazacağım konusunda bir fikrim var.
Guillaume


3
@antlersoft: Birbiri ardına uzun basit şeylerin listesini yapan 2.000 satırlık fonksiyon kesinlikle sorun değil ve bir mazerete ihtiyaç duymuyor. Lütfen "2.000 satır işlevi yazmamalısınız çünkü 2.000 satır işlevi yazmamalısınız" gibi dairesel değişkenlerle yanıt vermeyin.
16:02

Yanıtlar:


14

Sorunuzdan okuyabiliyorum sorun kod eski C değil, sadece kötü programlama değil. Ayrıntı düzeyi, devasa 2000+ satır işlevleri veya endişe ayrımı gibi bahsettiğiniz sorunların çoğu, herhangi bir dil, C veya Java için geçerlidir.

Hata işleme, hata işleme bağlamında belirtilmiştir. Sadece hata işleme kodu da kod olduğunu hatırlatabilir böylece bir örnek vermedi . Isıtıcı plaka kodunun tekrar eden bölümleri için bir mazeret yoktur. Faktörü dışarı; ya bir işleve ya da (ayrı bir işlev oluşturmaya değmezse) goto Error;deseni yapın ve hata işleme ve kaynak temizlemeyi Error:işlevin altındaki bir bölüme taşıyın .

Hatayı çağrı zincirinden geçirmek sorun gibi görünüyorsa, kendinize sorun: oradaki fonksiyonun gerçekten küçük bir adamın burada bir problemi olduğunu bilmesi gerekiyor mu? Bir dilde yerleşik istisna mekanizmaları bunu kolaylaştırır, ancak genel olarak istisnaları erken (herhangi bir dilde) ele almak daha iyidir, böylece hata durumu üst düzey kod mantığını kirletmez. Ve eğer oradaki fonksiyonun gerçekten bilmesi gerekiyorsa, ve ile istisnaları taklit etmenin yolları vardır .setjmplongjmp

Gerçekten C ile ilgili tek sorun standart kapların eksikliği olduğunu düşünüyorum. İken Set, genel olarak kutu sıralanmış bir dizi ve değiştirilebilir Mapbir çift dizi veya birlikte (çoğunlukla) bir struct(anahtar seti elden önce, biliyorsanız map[key] = valuedönüşler içine s.key = value), ancak gerçektir standardında dinamik dizi konteyner var kütüphane. C99'da en azından yığın ( int array[len]) üzerinde değişken uzunluklu bir dizi bildirebilirsiniz, ancak lenönceden hesaplamanız gerekir (genellikle zor değildir) ve elbette bunu yığın tahsisli nesne olarak döndüremezsiniz. Çoğu proje, kendi dinamik dizi kapsayıcılarını yazmak veya açık kaynaklı bir kapsayıcı benimsemekle sonuçlanır.

Kapanış notunda, orada olduğumu belirtmek isterim. Ben C ++ ve saf C taşındı Java programcısı oldum Ben "iyi C öğrenmek için X kitap okumak" tavsiye etmek istiyorum ama Java herhangi biri gibi herhangi bir yoktur. İlerlemenin yolu, dilin ve standart kütüphanenin tüm özelliklerini emmek; C'yi düşünmeye başlayana kadar çok google, çok okuyun ve çok kodlayın C'de Java'da yaptığınız gibi bir şeyler yazmaya çalışmak, doğrudan annenizden tercüme edilen kelimelerle yabancı bir dilde cümle yazmaya çalışmak kadar sinir bozucu dil; hem siz, hem de okuyucu sizi mahvedecektir. İyi haber şu ki, iyi programlama öğrenmek yavaş ama başka bir dil öğrenmek hızlı. Java'da düzgün kod yazarsanız,


1
Sonuçta, bu gerçekten iyi bir cevap. Sadece setjmp()/ longjmp()geçerli bir araç olarak görmeye itiraz ediyorum : Herhangi bir temizlik yapmaya bile çalışmaz. Herhangi bir ayırma sızdırılır, bekletilen kilit serbest bırakılmaz, açılan dosyalar kapatılmaz ve geçici veri tutarsızlıkları kalıcı hale gelir. IMHO, bu işlev çifti temelde icat edilen en kötü hack'tir ve tek başına bunu uygulamak mümkün olmuştur. Sonunda, C: açık hata kodlarında hata işlemeyi gerçekleştirmenin tek bir geçerli yolu var.
cmaster - eski haline monica

@cmaster yea. Şahsen, setjmp/longjmpC sudan çıkmış bir balık gibi görünüyor ve onları hiç kullanmadım. Sadece istisnaları taklit etmek için internette çok sayıda öğretici / kütüphane nedeniyle onları dahil etmek zorunda hissettim, bu yüzden gerçekten kullanan insanlar olduğunu düşündüm.
Bir Baykuş

7

Projenin iyi tarafı, kodun düz olmasıdır: çerçeve yok, çalışma zamanında bayt kodu manipülasyonu yok, AOP yok. Ve sunucu aynı anda java "merhaba dünya" tükürmek için gerekenden daha az bellek kullanarak tek bir makine ile 10000 + kullanıcılara cevap verebilir.

Bunun zaman ayırmaya değip değmeyeceğine ve şirketin düşük kod karmaşıklığı olan ve iyi performans gösteren çalışan bir yazılımı "modernize" etmek için kaynak harcayacağına dikkat etmenizi tavsiye ederim. Özellikle tanımadığınız bir sistem gibi göründüğünden, yeni hataları kendiniz tanıtacağınız yüksek bir başlık var.

Hâlâ bu rotada ilerlemek istiyorsanız aşağıdakileri öneririm:

  • Yazılımın / kodun durum diyagramını oluşturma (veya oluşturma)
  • Koda dalın ve sırasıyla kodun en karmaşık veya kritik kısımlarının bir listesini yapın
  • Bu kod tabanı hakkında bilgili birini bulun ve neden bu şekilde oluşturulduğunu ve soruna neden olduğu bilinenleri sorun
  • Öğrendiklerinizden belgeler yazın

Bu noktada, keşfetmeye değer olup olmadığına karar vereceksiniz. Şirketinizin kültürü başarısızlığı ödüllendirmezse, yeşil ışığı bir üst seviyeden veya bir yöneticiden alın.

  • Yazılımın farklı yapı taşlarını bölümlere ayırın ve her biri için birim testleri yazın.
  • Farklı modülleri birbirine yapışana kadar tekrarlayın
  • Gerçek kullanıcı etkileşimini simüle eden başka testler yapın (stres testleri vb.)

Bence bu oldukça iyi bir yol haritası ve sizi ihtiyacınız olan her yere götürüyor. Bu projenin özelliklerini bilmeden size çok yardımcı olmak zordur. Lütfen feragatnamemi aşırı alarmist olarak atmayın. Çok sayıda mükemmel programcı, mevcut bir projeyi en sevdikleri dile yeniden yazmaya çalışarak veya "modern" araçları kullanarak tozu dövdüler. Bu, dikkatle düşünülmesi gereken bir karardır ve sizi, yönetim desteği veya iş arkadaşlarınızdan yardım almadan hileli davranmamanızı ve kendi başınıza yapmamanızı tavsiye ederim.


2
Sorumun hiç net olmadığı gerçeğini hatırlıyorum. Kodu yeniden düzenlemek istemiyorum. Hiç. Mevcut kod tabanını olduğu gibi korumak istiyorum. Ancak yeni özellik için modern C yazmayı öğrenmek istiyorum. Ve burada kayboldum. Bulduğum belgelerin çoğu, 'modern' C yazma hakkında değil, C'de kodlama hakkında. Belki 'modern' C gibi bir şey yok ...
Guillaume

1

Daha üst düzey bir dil tercih ederseniz, C ++ veya Objective-C gibi C kodu ile kolayca karıştırılabilen bazı diller vardır.

Alternatif olarak, C ve C ++ makul şekilde uyumludur. Tüm kod tabanını sadece birkaç değişiklikle C ++ olarak derleyebilirsiniz - yeniden adlandırmanız gereken "class" veya "template" adlı ara sıra değişkene sahip olacaksınız, ancak pratikte hepsi bu olacak. (sizeof ('a') C ve C ++ 'da farklıdır, ancak bunu hiç kullandığımı sanmıyorum).

Bu rotaya giderseniz, bir sonraki bakımcının C ++ ile çok akıcı olmayabileceğini düşünün. Uzaklaşma. C ++ 'dan yararlanın, ancak şimdiye kadar bir C programcısı kolayca anlayabilir.


1
Katılmıyorum. C ve C ++ farklı dillerdir ve C ++ derleyicisinin gerektirdiği bazı kodlar (açıkça dönüş değerini döküm malloc) C'de kötü uygulama olarak kabul edilir constve C ve C ++ arasındaki anlam inlineda çok farklıdır ve tabii ki C ++ __restrict. Her ikisinde de derlenen kaynakların alt kümesinde bile dilleri birbirinin yerine geçebilir olarak düşünmeyin.
Angew artık SO ile

1

Temel olarak, iyi C kodu yazmak iyi C ++ veya Java kodu yazmakla aynıdır: Bir sınıf istiyorsunuz, a kullanın struct. Kalıtım istiyorsanız, üssü structilk isimsiz bir üye olarak ekleyin . Sanal işlevler istiyorsanız struct, işlev işaretleyicilerinin statikine bir işaretçi ekleyin . Ve benzeri, vb C ++ başlık altında tam olarak ne yapar, tek fark, C açıktır. Böylece, C mükemmel nesne odaklı programlama yapabilirsiniz, sadece biraz daha farklı ve daha kazancı görünüyor alışkın.

Mesele şu ki, iyi programlama dil özellikleriyle değil paradigmalar ile ilgilidir. Doğru, dil özelliklerinizin kullanmak istediğiniz paradigmalar için iyi bir destek sağlaması her zaman iyidir, ancak dil özellikleri bir gereklilik değildir. Bunu fark ettikten sonra, hemen hemen her dilde iyi bir kod yazabilirsiniz (brainfuck veya INTERCAL gibi bazı ezoterik diller dışında).

Elbette, sorun, standart C kütüphanesinin alışık olduğunuz şık konteyner sınıflarından hiçbirini içermemesidir. Ne yazık ki, dinamik olarak ayrılmış diziler kullanarak ya kendi başınıza kullanmanız ya da bu eksikliği gidermeniz gerekir. Ama yakında öğreneceğinize eminim, gerçekten ihtiyacınız olan tek şey dinamik diziler ( malloc()) ve sınıflarınızdaki işaretçi üyeleri aracılığıyla uygulanan bağlantılı listeler / ağaçlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.