C = ++ (a + b) neden derleme hatası veriyor?


111

Araştırdıktan sonra, artırma operatörünün işlenenin değiştirilebilir bir veri nesnesine sahip olmasını gerektirdiğini okudum: https://en.wikipedia.org/wiki/Increment_and_decrement_operators .

Bundan derleme hatası verdiğini tahmin ediyorum çünkü (a+b)geçici bir tamsayıdır ve bu yüzden değiştirilebilir değildir.

Bu anlayış doğru mu? İlk defa bir problemi araştırmaya çalışıyordum, bu yüzden aramam gereken bir şey varsa lütfen tavsiye edin.


35
Araştırma açısından fena değil. Doğru yoldasın.
StoryTeller - Unslander Monica

35
İfadenin ne yapmasını bekliyorsunuz?
qrdl

4
C11 standardı 6.5.3.1'e göre: Önek artırma veya azaltma operatörünün işleneni atomik, nitelikli veya niteliksiz gerçek veya işaretçi tipine sahip olacak ve değiştirilebilir bir ldeğer olacaktır
Christian Gibbons

10
1'in a ve b arasında dağıtılmasını nasıl istersiniz? "Dizi indeksleri 0 veya 1'den başlamalı mı? 0,5'lik uzlaşmam uygun bir değerlendirme yapılmadan reddedildi, diye düşündüm." - Stan Kelly-Bootle
Andrew Morton

5
Sanırım bir sonraki soru, c = a + b + 1niyetinizi daha net hale getirirken ve aynı zamanda yazmak için daha kısa olduğunda neden bunu yapmak isteyesiniz? Arttırma / azaltma operatörleri iki şey yapar: 1. kendileri ve argümanları bir ifade oluşturur (örneğin for döngüsünde kullanılabilir), 2. argümanı değiştirirler. Örneğinizde, değiştirilmiş bağımsız değişkeni attığınız için, özellik 1'i kullanıyorsunuz, ancak özellik 2'yi kullanmıyorsunuz. Özellik 2'ye ihtiyacınız yoksa ve sadece ifadeyi istiyorsanız, o zaman sadece bir ifade yazabilirsiniz, örneğin x ++ yerine x + 1.
Trevor

Yanıtlar:


117

Bu sadece bir kural, hepsi bu ve muhtemelen (1) C derleyicileri yazmayı kolaylaştırmak ve (2) hiç kimse C standartları komitesini onu gevşetmeye ikna etmedi.

Gayrı yalnızca yazabilirsiniz konuşan ++fooeğer foogibi bir görev ifadesinin sol tarafında görünebilir foo = bar. Yazamadığın a + b = bariçin yazamazsın ++(a + b).

a + bÜzerinde ++çalışabilecek geçici bir süre verilememesinin gerçek bir nedeni yoktur ve bunun sonucu, ifadenin değeridir ++(a + b).


4
Sanırım (1) noktası çiviye kafaya çarpıyor. Sadece C ++ 'da geçici materyalizasyon kurallarına bakmak bile kişinin midesini döndürebilir (ama güçlü olsa da, bunu söylemeliyim).
StoryTeller - Unslander Monica

4
@StoryTeller: Gerçekten, sevgili dilimiz C ++ 'dan farklı olarak, C hala nispeten önemsiz bir şekilde derleniyor.
Bathsheba

29
İşte IMHO'nun gerçek bir nedeni: ++Bazen bir şeyi değiştirmenin yan etkisine sahip olsaydı ve bazen yapmasaydı bu korkunç bir kafa karışıklığı olurdu .
aschepler

5
@dng: Gerçekten öyle; bu yüzden lvalue ve rvalue terimleri, günümüzde işler bundan daha karmaşık olsa da (özellikle C ++ 'da) tanıtıldı. Örneğin, bir sabit asla bir l değeri olamaz: 5 = a gibi bir şey anlamsızdır.
Bathsheba

6
@Bathsheba Bu, 5 ++ 'nın neden bir derleme hatasına neden olduğunu açıklıyor
dng

40

C11 standardı bölüm 6.5.3.1'de belirtilmektedir.

Önek artırma veya azaltma operatörünün işlenen atomik, nitelikli veya nitelenmemiş gerçek veya işaretçi tipine sahip olacak ve değiştirilebilir bir değer olacaktır.

Ve "değiştirilebilir değer" bölüm 6.3.2.1 alt bölüm 1'de açıklanmıştır.

Bir lvalue, potansiyel olarak bir nesneyi belirten bir ifadedir (void dışında bir nesne türü olan); bir lvalue değerlendirildiğinde bir nesneyi belirtmiyorsa, davranış tanımsızdır. Bir nesnenin belirli bir türe sahip olduğu söylendiğinde, tür, nesneyi belirtmek için kullanılan ldeğer ile belirlenir. Değiştirilebilir bir ldeğer, dizi türüne sahip olmayan, tamamlanmamış bir türe sahip olmayan, const nitelikli bir türü olmayan ve bir yapı veya birleşim ise herhangi bir üyesi olmayan (özyinelemeli olarak herhangi bir üye dahil) bir ldeğerdir. veya içerdiği tüm kümelerin veya birleşimlerin öğesi) sabit nitelikli bir türle.

Bu nedenle (a+b), değiştirilebilir bir değer değildir ve bu nedenle, önek artış operatörü için uygun değildir.


1
Bu tanımlardan çıkardığınız sonuç eksik ... (a + b) 'nin potansiyel olarak bir nesneyi belirtmediğini söylemek istiyorsunuz, ancak bu paragraflar buna izin vermiyor.
hkBst

21

Haklısın. ++Orijinal değişkene yeni değer atamak çalışır. Yani ++adeğerini alacak, ona aekleyecek 1ve sonra tekrar atayacaktır a. Dediğiniz gibi, (a + b) geçici bir değer olduğundan ve bellek adresi atanmış bir değişken olmadığından, atama gerçekleştirilemez.


12

Bence çoğunlukla kendi sorunuzu cevapladınız. İfadenizde küçük bir değişiklik yapabilirim ve "geçici değişkeni" C. Gibbons'ın da bahsettiği gibi "rvalue" ile değiştirebilirim.

Değişken, bağımsız değişken, geçici değişken vb. Terimler, C'nin bellek modelini öğrendikçe daha net hale gelecektir (bu, güzel bir genel bakışa benziyor: https://www.geeksforgeeks.org/memory-layout-of-c-program/ ).

"Rvalue" terimi yeni başladığınızda opak görünebilir, bu nedenle aşağıdakilerin bununla ilgili bir sezgi geliştirmenize yardımcı olacağını umuyorum.

Lvalue / rvalue, bir eşittir işaretinin (atama operatörü) farklı taraflarından bahsediyor: lvalue = sol taraf (küçük harf L, "bir" değil) rvalue = sağ taraf

C'nin hafızayı (ve kayıtları) nasıl kullandığı hakkında biraz bilgi edinmek, ayrımın neden önemli olduğunu anlamaya yardımcı olacaktır. Gelen geniş fırça darbeleriyle , derleyici bir ifadesi (rvalue) sonucunu hesaplamak makine dili talimatları listesini oluşturur ve ardından koyar o sonuç bir yere (lvalue). Aşağıdaki kod parçasıyla ilgilenen bir derleyici düşünün:

x = y * 3

Montaj pseudocode o olabilir bu oyuncak örneğe benzer:

load register A with the value at memory address y
load register B with a value of 3
multiply register A and B, saving the result in A
write register A to memory address x

++ operatörü (ve onun - karşılığı) değiştirmek için bir "bir yere" ihtiyaç duyar, esasen bir değer olarak çalışabilen herhangi bir şey.

C bellek modelini anlamak yardımcı olacaktır çünkü argümanların işlevlere nasıl aktarıldığı ve (sonunda) malloc () işlevi gibi dinamik bellek ayırma ile nasıl çalışılacağı hakkında kafanızda daha iyi bir fikir edineceksiniz. Benzer nedenlerle, derleyicinin ne yaptığı hakkında daha iyi bir fikir edinmek için bir noktada bazı basit montaj programlarını inceleyebilirsiniz. Ayrıca gcc kullanıyorsanız , -S seçeneği "Doğru derleme aşamasından sonra durdurun; birleştirmeyin." ilginç olabilir (yine de küçük bir kod parçası üzerinde denemenizi tavsiye ederim ).

Bir kenara olarak: ++ talimatı 1969'dan beri var (C'nin selefi B'de başlamasına rağmen):

(Ken Thompson'ın) gözlemi, ++ x'in çevirisinin x = x + 1'den daha küçük olduğuydu. "

Bu wikipedia referansının ardından, sizi Dennis Ritchie'nin C dilinin tarihi üzerine yazdığı ilginç bir yazıma ("K&R C" deki "R"), kolaylık sağlamak için buraya bağlantıya götürecektir: http://www.bell-labs.com/ usr / dmr / www / chist.html burada "++" için arama yapabilirsiniz.


6

Bunun nedeni, standardın işlenenin bir ldeğer olmasını gerektirmesidir. İfade (a+b)bir ldeğer değildir, bu nedenle artırma operatörünün uygulanmasına izin verilmez.

Şimdi, biri "Tamam, gerçekten de nedeni bu, ama aslında bundan başka * gerçek * bir neden yok" diyebilir , ama ne yazık ki operatörün gerçekte nasıl çalıştığına dair özel ifade , durumun böyle olmasını gerektiriyor.

++ E ifadesi, (E + = 1) ile eşdeğerdir.

Açıkçası, yazamıyorum E += 1eğer Ebir lvalue değildir. Bu utanç verici çünkü biri şöyle diyebilirdi : "E'yi birer birer artırır" ve yapılabilir. Bu durumda, derleyiciyi biraz daha karmaşık hale getirme pahasına, operatörü l-olmayan bir değere uygulamak (prensipte) mükemmel bir şekilde mümkün olacaktır.

Şimdi, tanım önemsiz bir şekilde yeniden ifade edilebilir (bence orijinal olarak C değil, B'nin yadigarı), ancak bunu yapmak, dili temelde eski sürümleriyle artık uyumlu olmayan bir şeye değiştirecektir. Olası fayda oldukça küçük olduğu, ancak olası çıkarımları çok büyük olduğu için, bu asla gerçekleşmedi ve muhtemelen asla olmayacak.

C'ye ek olarak C ++ 'ı da düşünürseniz (soru C olarak etiketlenmiştir, ancak operatör aşırı yükleri hakkında tartışma olmuştur), hikaye daha da karmaşık hale gelir. C'de, durumun böyle olabileceğini hayal etmek zordur, ancak C ++ 'da sonucu (a+b)pek de arttıramayacağınız bir şey olabilir veya artış çok önemli yan etkilere sahip olabilir (sadece 1 eklemek değil). Derleyici bununla başa çıkabilmeli ve sorunlu durumları ortaya çıktıkça teşhis edebilmelidir. Bir değerde, bu hala kontrol edilmesi biraz önemsiz. Zavallı şeye attığınız bir parantez içindeki herhangi bir gelişigüzel ifade için öyle değil.
Bu, yapamamasının gerçek bir nedeni değil yapılabilir, ancak bunu uygulayanların neden çok az kişiye çok az fayda vaat eden böyle bir özelliği eklemek için tam olarak kendinden geçmiş olmadıklarını açıklıyor.



3

++ değeri orijinal değişkene vermeye çalışır ve (a + b) geçici bir değer olduğu için işlemi gerçekleştiremez. Ve temelde programlamayı kolaylaştırmak için C programlama kurallarının kurallarıdır. Bu kadar.


2

++ (a + b) ifadesi gerçekleştirildiğinde, örneğin:

int a, b;
a = 10;
b = 20;
/* NOTE :
 //step 1: expression need to solve first to perform ++ operation over operand
   ++ ( exp );
// in your case 
   ++ ( 10 + 20 );
// step 2: result of that inc by one 
   ++ ( 30 );
// here, you're applying ++ operator over constant value and it's invalid use of ++ operator 
*/
++(a+b);
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.