Neden bir satırı bir satırda değişken ilan edip bir sonraki adımda ona atayın?


101

Sık sık C ve C ++ kodunda aşağıdaki kuralları görüyorum:

some_type val;
val = something;

some_type *ptr = NULL;
ptr = &something_else;

onun yerine

some_type val = something;
some_type *ptr = &something_else;

Başlangıçta bunun, tüm yerel değişkenleri kapsamın en üstünde açıklamak zorunda olduğunuz günlerden kalan bir alışkanlık olduğunu varsaydım. Ancak kıdemli geliştiricilerin alışkanlıklarını bu kadar çabuk işten çıkarmamayı öğrendim. Peki, bir satırda bildirmek ve daha sonra atamak için iyi bir sebep var mı?


12
+1 "Eski geliştiricilerin alışkanlıklarını bu kadar çabuk reddetmemeyi öğrendim." Öğrenmesi akıllıca bir ders.
Wildcard

Yanıtlar:


92

C

C89'da tüm bildirimler bir kapsamın başında olmak zorundaydı ( { ... }), ancak bu gereksinim hızlı bir şekilde (ilk önce derleyici uzantılarıyla ve daha sonra standartla birlikte) iptal edildi.

C ++

Bu örnekler aynı değil. Varsayılan yapıcıyı ve ardından işlevi çağırırken some_type val = something;kopya kurucuyu val = something;çağırır operator=. Bu fark genellikle kritiktir.

Alışkanlıkları

Bazı insanlar ilk önce değişkenleri bildirmeyi ve daha sonra kodlarını daha sonra bir noktada bildirimleri ve bir diğerinde tanımlarını kullanarak yeniden biçimlendirmeleri durumunda tanımlamayı tercih eder.

İşaretçiler hakkında, bazı insanlar o işaretçiyle ne yaparlarsa yapsınlar, her işaretçiyi NULLveya bu işaretçiyi başlatma alışkanlığına sahipler nullptr.


1
C ++ için büyük ayrım, teşekkürler. Peki ya düz C?
Jonathan Sterling

13
MSVC'nin hala C modunda derlendiğinde bir bloğun başlangıcı dışında bildirimleri desteklememesi benim için sonsuz tahriş kaynağıdır.
Michael Burr

5
@ Michael Burr: Bunun nedeni MSVC'nin C99'u hiç desteklememesidir.
orlp

3
o:; "some_type val = şey kopya yapıcı çağrıları" olabilir geçici bir val inşaat ve yıkım kopyalayıp doğrudan val bir kullanarak inşa, kopyalama kurucusunu çağırmak, ancak standart bir tempory varsayılan-inşaat elide için derleyici verir some_typeyapıcı something, tek argüman olarak alıyor . Bu, C ++ 'ta çok ilginç ve sıradışı bir durum ... bu işlemlerin anlamsal anlamı hakkında bir varsayım olduğu anlamına geliyor.

2
@Aerovistae: Yerleşik tipler için aynıdır, ancak kullanıcı tanımlı türler için her zaman söylenemez.
orlp

27

Sorunuzu C ve C ++ ile aynı anda etiketlediniz, bununla birlikte cevap bu dillerde oldukça farklı.

İlk olarak, sorunuzun başlığının ifadesi yanlıştır (ya da daha doğrusu sorunun kendisiyle ilgisi yoktur). Her iki örneğinizde değişken aynı anda, tek bir satırda bildirilir ve tanımlanır . Örnekleriniz arasındaki fark, ilkinde, değişkenlerin başlatılmamış bırakılması veya kukla bir değerle başlatılmasıdır ve daha sonra anlamlı bir değerin atanmasıdır . İkinci örnekte, değişkenler hemen başlatılır .

İkincisi, C ++ dilinde, @ nightcracker'ın cevabında belirtildiği gibi, bu iki yapı anlamsal olarak farklıdır. Birincisi, ilkini yaparken atama üzerine, ikincisi ise atama üzerine güveniyor. C ++ 'da bu işlemler aşırı yüklenebilir ve bu nedenle potansiyel olarak farklı sonuçlara yol açabilir (bir tanesi eşdeğer olmayan başlatma ve tahsis aşırı yüklerinin üretilmesinin iyi bir fikir olmadığını belirtebilir).

Orijinal standart C dilinde (C89 / 90) bloğun ortasındaki değişkenleri bildirmek yasa dışıdır; bu nedenle, blokların başında başlatılmamış (veya yapay değerlerle başlatılmış) ve ardından anlamlı atanmış değişkenler görebilirsiniz Değerler sonra, bu anlamlı değerler mevcut olduğunda.

C99 dilinde değişkenleri bloğun ortasına bildirmek uygundur (tıpkı C ++ 'da olduğu gibi); (Bu, C ++ için de geçerlidir).


2
@Jonathan Sterling: Örneklerini okudum. Muhtemelen C ve C ++ dillerinin standart terminolojisini tazelemeniz gerekir. Özellikle, bu dillerde özel anlamları olan beyan ve tanım terimlerinde . Tekrar edeceğim: her iki örneğinizde değişkenler bir satırda bildirilmiş ve tanımlanmıştır. C / C ++ 'da satır some_type val;hemen bildirir ve değişkeni tanımlarval . Cevabımda demek istediğim bu.

1
Orada ne demek istediğini anlıyorum. Onları benim kullandığım şekilde anlamsız olarak ilan etmek ve tanımlamak konusunda kesinlikle haklısınız . Umarım fakir ifadelerden ve kötü düşünülmüş yorumlardan dolayı özürlerimi kabul edersiniz.
Jonathan Sterling

1
Bu yüzden, eğer fikir birliği “ilan etmek” yanlış kelime ise, standart hakkında daha iyi bilgiye sahip birisinin Wikibooks sayfasını düzenlemekten daha iyi olduğunu öneriyorum.
Jonathan Sterling

2
Başka herhangi bir bağlamda beyan, doğru bir kelime olacaktır, ancak beyan, iyi tanımlanmış bir kavram olduğu için , sonuçlarla, C ve C ++ 'da, diğer bağlamlarda olabildiğince gevşek kullanamazsınız.
orlp

2
@ ybungalobill: Yanlışsın. C / C ++ 'da beyan ve tanım , birbirini dışlayan kavramlar değildir. Aslında, tanım sadece belirli bir bildirim biçimidir . Her tanım aynı anda bir bildiridir (birkaç istisna hariç). Tanımlayıcı beyanlar (yani tanımlamalar) ve tanımlayıcı olmayan beyanlar vardır. Dahası, normal olarak termik beyanname (tanım olsa bile), ikisi arasındaki farkın kritik olduğu bağlamlar hariç, her zaman kullanılır.

13

Bence bu eski bir alışkanlık, "yerel deklarasyon" zamanından kalanlar. Ve bu nedenle sorunuza cevap olarak: Hayır, iyi bir sebep olduğunu sanmıyorum. Asla kendim yapmam.


4

Ben de bu konuda bir şeyler söyledi cevabım için Helium3 tarafından bir soruya .

Temel olarak, neyin değiştiğini kolayca görmenin görsel bir yardım olduğunu söylüyorum.

if (a == 0) {
    struct whatever *myobject = 0;
    /* did `myobject` (the pointer) get assigned?
    ** or was it `*myobject` (the struct)? */
}

ve

if (a == 0) {
    struct whatever *myobject;
    myobject = 0;
    /* `myobject` (the pointer) got assigned */
}

4

Diğer cevaplar oldukça iyi. Bunun C civarında bir geçmişi var. C ++ 'da bir yapıcı ile bir atama operatörü arasındaki fark var.

Hiç kimsenin ek noktadan bahsetmediğine şaşırdım: beyannamelerin değişken kullanmaktan ayrı tutulması bazen çok daha okunaklı olabilir.

Görsel olarak konuşursak, kodları okurken, değişkenlerin türleri ve adları gibi daha sıradan eserler size sıçrayan şey değildir. Bu var ifadeleri size bakarken en çok vakit geçirmek ve böylece geri kalanı üzerinde bakışta eğilimi var, genellikle en çok ilgilendiğiniz.

Aynı sıkı alanda devam eden bazı türler, isimler ve ödevlerim varsa, bu biraz bilgi yüklemesi olabilir. Ayrıca, uzayda göz attığım alanda önemli bir şeyin olduğu anlamına geliyor.

Söylemesi biraz karşı sezgisel görünebilir, ancak bu kaynağınızın daha fazla dikey alan kaplamasının daha iyi hale getirebileceği bir örnektir. Bunu neden sık sık işaretçi aritmetik ve sıkışık bir dikey alanda atama yapan sıkışık dolgulu satırlar yazmamanıza benzer olarak görüyorum - sadece dil böyle şeylerden uzaklaşmanıza izin verdiği için her zaman. :-)


2

C'de bu standart pratikti çünkü değişkenler, fonksiyonun başlangıcında, C ++ 'dan farklı olarak, fonksiyon gövdesinde daha sonra kullanılacak herhangi bir yerde ilan edilebilecekleri beyan edilmek zorundaydı. İşaretçiler 0 ya da NULL olarak ayarlandı, çünkü sadece işaretçinin hiçbir çöpü göstermediğinden emin oldu. Aksi takdirde, kimseyi böyle yapmaya zorlayan, düşünebildiğim önemli bir avantaj yoktur.


2

Değişken tanımları yerelleştirmek ve anlamlı bir şekilde başlatılmaları için artılar:

  • değişkenlere alışılmış bir şekilde kodda ilk kez göründüğünde anlamlı bir değer atanırsa (aynı şeyin başka bir perspektifi: anlamlı bir değer elde edilinceye kadar görünümlerini geciktirirsiniz), o zaman yanlışlıkla anlamsız veya başlangıçsız bir değerle kullanılma şansı yoktur ( Kolayca gerçekleşebilecek olan durum, koşullu ifadeler, kısa devre değerlendirmesi, istisnalar vb.

  • daha verimli olabilir

    • başlangıç ​​değerinin ayarlanması genel giderlerini önler (varsayılan inşaat veya NULL gibi bazı sentinel değerlerine ilklendirme)
    • operator= bazen daha az verimli olabilir ve geçici bir nesne gerektirebilir
    • Bazen (özellikle, satır içi işlevler için), optimize edici bazı / tüm verimsizlikleri kaldırabilir

  • değişkenlerin kapsamını minimize etmek, kapsamda eşzamanlı olarak ortalama değişken sayısını minimize eder : bu

    • o yapar daha kolay zihinsel izlemek için kapsam değişkenleri, bu değişkenleri etkileyebilecek yürütme akışları ve ifadeleri ve bunların değerinin ithalat
    • en azından bazı karmaşık ve opak nesneler için bu , programın kaynak kullanımını (yığın, iş parçacığı, paylaşılan bellek, tanımlayıcılar) azaltır
  • Bir tanımda değişken ismini, sonra da ilk anlamlı atamayı tekrarlamadığınız için bazen daha kısa

  • Referanslar gibi belirli türler için ve nesnenin ne zaman olmasını istediğinizde const

Değişken tanımlarını gruplamak için değişkenler:

  • bazen bir dizi değişkenin türünü saptamak elverişli ve / veya özlüdür :

    the_same_type v1, v2, v3;

    (Sebep sadece tür adının aşırı uzun veya karmaşık typedefolması durumunda, bazen daha iyi olabilir)

  • Bazen, bazı işlemlerde yer alan değişkenleri (ve türlerini) vurgulamak için değişkenlerini kullanımlarından bağımsız olarak gruplandırmak istenebilir:

    type v1;
    type v2; type v3;

    Bu, türün ortaklığına vurgu yapar ve bunları kopyalamayı biraz daha kolay hale getirirken, yine de satır başına bir değişkene yapıştırarak kopyala-yapıştır, //yorum yap vb.

Programlamada çoğu zaman olduğu gibi, çoğu durumda bir uygulamanın net bir ampirik faydası varken, diğer uygulama birkaç durumda gerçekten çok daha iyi olabilir.


Daha fazla dilde, kodun başka bir yerde asla yazılmayacak bir değişkenin değerini bildirdiği ve belirlediği durumları ayırt etmesini diliyorum, ancak yeni değişkenler aynı adı kullanabiliyorlardı [örneğin, davranış daha sonra ifadelerde aynı değişkeni kullanıp kullanmadığı aynı ya da farklı bir], kodun birden fazla yerde yazılabilmesi gereken bir değişken oluşturduğulardan. Her iki kullanım durumu da aynı şekilde yürütülürken, değişkenlerin ne zaman değişebileceğini bilmek hataları tespit etmeye çalışırken çok yararlıdır.
supercat
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.