C ve C ++ 'da, hangi yöntemler denkliğin (==) gerekli olduğu (=) ödevinin yanlışlıkla kullanılmasını önleyebilir?


15

C ve C ++ 'da, aşağıdaki kodu ciddi bir hatayla yazmak çok kolaydır.

char responseChar = getchar();
int confirmExit = 'y' == tolower(responseChar);
if (confirmExit = 1)
{
    exit(0);
}

Hata, if ifadesinin olması gerektiğidir:

if (confirmExit == 1)

Kodlanmış olarak, her seferinde çıkacaktır, çünkü confirmExitdeğişkenin ataması gerçekleşir, ardından confirmExitifadenin sonucu olarak kullanılır.

Bu tür bir hatayı önlemenin iyi yolları var mı?


39
Evet. Derleyici uyarılarını açın. Uyarıları hata olarak kabul edin ve bu bir sorun değildir.
Martin York


9
Verilen örnekte, çözüm kolaydır. Bu değere bir boolean değeri atarsınız, böylece bir boolean: olarak kullanırsınız if (confirmExit).
Güvenli

4
Sorun şu ki, hata atama operatörü için = ve eşitlik karşılaştırması için == kullanmayı seçtiklerinde C dili "tasarımcıları" tarafından yapılmıştır. ALGOL şunları kullandı: =, çünkü eşitlik karşılaştırması için = kullanmak istediler ve PASCAL ve Ada ALGOL kararını izlediler. (DoD, DoD1 fırına C tabanlı bir giriş istediğinde, sonunda Ada verdi, Bell Labs'ın "C artık değildi ve DoD görev açısından kritik öneme sahip olacak kadar sağlam olmayacağını" söyledi. DoD ve müteahhitlerin Bell Labs'ı bu konuda dinlemelerini diler.)
John R. Strohm

4
@John, sembollerin seçimi sorun değil, atamaların da atanan değeri döndüren, bir koşulun içine a = bveya a == biçine izin veren bir ifade olması .
Karl Bielefeldt

Yanıtlar:


60

En iyi teknik derleyicinizin uyarı seviyesini arttırmaktır. Daha sonra, eğer koşullu ise potansiyel atama konusunda sizi uyaracaktır.

Kodunuzu sıfır uyarılarla derlediğinizden emin olun (yine de yapmanız gerekir). Bilgiçlik taslamak istiyorsanız, derleyicinizi uyarıları hata olarak değerlendirecek şekilde ayarlayın.

Yoda koşullarını kullanmak (sabiti sol tarafa koymak) on yıl önce popüler olan başka bir teknikti. Ancak kodu okumayı zorlaştırırlar (ve böylece okudukları doğal olmayan yoldan dolayı (Yoda değilseniz)) ve uyarı düzeyini arttırmaktan daha fazla fayda sağlamazlar (ayrıca daha fazla uyarının ekstra faydaları vardır).

Uyarılar koddaki gerçekten mantıklı hatalardır ve düzeltilmesi gerekir.


2
Kesinlikle uyarılara gidin, Yoda şartlarına değil - koşullu sabiti ilk önce yapabileceğiniz kadar kolay = = yapmayı unutabilirsiniz.
Michael Kohne

8
Bu soru için en çok oylanan cevabın 'derleyici uyarılarını hatalara dönüştür' olması hoş bir sürpriz oldu. Korkuyu bekliyordum if (0 == ret).
James

2
@James: ... işe yaramayacağından bahsetmiyorum a == b!
Emilio Garavaglia

6
@EmilioGaravaglia: Bunun için kolay bir çözüm var: Sadece yazın 0==a && 0==b || 1==a && 1==b || 2==a && 2==b || ...(tüm olası değerler için tekrarlayın). Zorunlu ...|| 22==a && 22==b || 23==a && 24==b || 25==a && 25==b ||... hatasını unutmayın , aksi takdirde bakım programcıları hiç eğlenmez.
user281377

10

Yazılımınızı test etmek gibi her zaman radikal bir şey yapabilirsiniz. Otomatik birim testleri bile demek istemiyorum, sadece deneyimli her geliştiricinin yeni kodunu iki kez çalıştırarak alışkanlıktan çıktığı testler, bir kez çıkış onaylandı ve bir kez değil. Çoğu programcının bunu bir sorun olarak görmemesinin nedeni budur.


1
Programınızın davranışı tamamen deterministik olduğunda yapmak kolaydır.
James

3
Bu özel konuyu test etmek zor olabilir. rc=MethodThatRarelyFails(); if(rc = SUCCESS){Özellikle yöntem sadece test edilmesi zor koşullarda başarısız olursa, insanların birden fazla ısırıldığını gördüm .
Robotu Gort

3
@StevenBurnap: Sahte nesneler bunun içindir. Doğru test, arıza modlarının testini içerir.
Jan Hudec

Bu doğru cevap.
Monica ile

6

İfade içinde atamaların yanlış kullanımını önlemenin geleneksel bir yolu sabiti sola, değişkeni sağa yerleştirmektir.

if (confirmExit = 1)  // Unsafe

if (1=confirmExit)    // Safe and detected at compile time.

Derleyici, aşağıdakine benzer bir sabite geçersiz bir atama hatası bildirir.

.\confirmExit\main.cpp:15: error: C2106: '=' : left operand must be l-value

Gözden geçirilmiş durum şöyle olur:

  if (1==confirmExit)    

Aşağıdaki yorumlarda gösterildiği gibi, bu birçok kişi tarafından uygunsuz bir yöntem olarak kabul edilir.



13
Bir şeyleri bu şekilde yapmanın sizi oldukça popüler olmayacağına dikkat edilmelidir.
riwalk

11
Lütfen bu uygulamayı önermeyin.
James

5
İki değişkeni birbiriyle karşılaştırmanız gerekirse de çalışmaz.
dan04

Bazı diller aslında yeni bir değere 1 atanmasına izin veriyor (evet, Q'nun bir c / c ++ olduğunu biliyorum)
Matsemann

4

Herkes "derleyici uyarıları" diyerek katılıyorum ama başka bir teknik eklemek istiyorum: Kod değerlendirmeleri. Taahhüt edilen tüm kodları, tercihen tamamlanmadan önce gözden geçirme politikanız varsa, muhtemelen bu tür bir şey inceleme sırasında yakalanır.


Katılmıyorum. Özellikle = = yerine = kodu gözden geçirerek kolayca geçebilirsiniz.
Simon

2

İlk olarak, uyarı seviyenizi yükseltmek asla acıtmaz.

Eğer koşulunuzun if ifadesinin içindeki bir ödevin sonucunu test etmesini istemiyorsanız, yıllar boyunca birçok C ve C ++ programcısıyla çalışmış ve sabitin ilk önce karşılaştırıldığını hiç duymamışsınızdır. if(1 == val) kötü bir şey , bu yapıyı deneyebilir.

Proje lideriniz bunu yaptığınızı onaylarsa, diğer insanların ne düşündüğü konusunda endişelenmeyin. Gerçek kanıt, siz veya bir başkasının kodunuzu aylar ve yıllar sonra anlamlandırabileceğidir.

Bununla birlikte, bir ödevin sonucunu test etmek istiyorsanız, daha yüksek uyarılar kullanmak ödevi bir sabite takmış olabilir (muhtemelen).


Yoda koşullu gören ve hemen anlamayan yeni başlayan herhangi bir programcıya şüpheci bir kaş kaldırıyorum. Bu sadece bir kapak, okunması zor değil ve bazı yorumların iddia ettiği kadar kötü değil.
underscore_d

@underscore_d İşverenlerimin çoğunda, bir koşullu görevlendirmeler kaşlarını çattı. Düşünme, ödevi şartlıdan ayırmanın daha iyi olmasıydı. Başka bir kod satırı pahasına olsa bile daha net olmanın nedeni, devam eden mühendislik faktörüdür. Büyük kod tabanları ve çok sayıda bakım birikimi olan yerlerde çalıştım. Birinin bir değer atamak isteyebileceğini tamamen anlıyorum ve atamadan kaynaklanan koşulda dal. Perl'de daha sık yapıldığını görüyorum ve niyet açıksa, yazarın tasarım desenini takip edeceğim.
octopusgrabbus

Ben sadece Yoda koşullarını düşünüyordum (burada demo gibi), ödevle değil (OP'de olduğu gibi). Birincisini önemsemiyorum ama ikincisini de sevmiyorum. Kasten kullandığım tek biçim , döküm başarısız olursa kapsamı if ( auto myPtr = dynamic_cast<some_ptr>(testPtr) ) {işe yaramaz hale getirmekten kaçınmaktır nullptr- muhtemelen C ++ 'nın bir koşullu olarak atama yeteneğinin sınırlı olmasının nedeni budur. Geri kalanı için, evet, bir tanımın kendi çizgisini alması gerektiğini söyleyebilirim - bir bakışta görmek çok daha kolay ve çeşitli akıl kayıplarına daha az eğilimli.
underscore_d

@underscore_d Yorumlarınıza dayanarak cevap düzenlenmiştir. İyi bir nokta.
octopusgrabbus

1

Partiye her zamanki gibi geç, ama burada Statik Kod Analizi anahtar

Çoğu IDE derleyicinin sözdizimsel kontrolü üzerinde ve üzerinde SCA sağlar ve MISRA (*) ve / veya CERT-C yönergelerini uygulayanlar da dahil olmak üzere başka araçlar da mevcuttur.

Beyan: MISRA C çalışma grubunun bir üyesiyim, ancak kişisel sıfatla gönderiyorum. Ayrıca herhangi bir araç satıcısından bağımsızım


-2

Sadece sol taraftaki atamayı kullanın, derleyici uyarıları yardımcı olabilir, ancak doğru seviyeye ulaştığınızdan emin olmanız gerekir, aksi takdirde anlamsız uyarılarla gömüleceksiniz veya görmek istedikleriniz söylenmeyecektir.


4
Modern derleyicilerin ne kadar anlamsız uyarı ürettiğine şaşıracaksınız. Bir uyarının önemli olduğunu düşünmeyebilirsiniz, ancak çoğu durumda yanılıyorsunuz.
Kristof Provost

"Katı Kod Yazma" adlı kitaba göz atın amazon.com/Writing-Solid-Microsoft-Programming-Series/dp/… . Derleyiciler ve uyarı mesajlarından ne kadar fayda sağlayabileceğimiz ve hatta daha kapsamlı statik analiz hakkında büyük bir tartışma ile başlar.
DeveloperDon

@KristofProvost Görsel stüdyoya aynı kod satırından aynı uyarının 10 kopyasını vermeyi başardım, sonra bu sorun 'düzeltildiğinde' aynı kod satırı hakkında 10 özdeş uyarı ile sonuçlandı. orijinal yöntem daha iyiydi.
Ters Lama
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.