Ödev ve eşitlik kontrolünü birleştiren bu if-ifadesi neden doğrudur?


216

Yeni başlayanlar için bazı hatalar düşünüyordum ve ififadenin sonunu buldum . Bu kodu biraz genişletti:

int i = 0;
if (i = 1 && i == 0) {
    std::cout << i;
}

Bunu gördük ifdeyimi döndürür gerçek ve cout's iolarak 1. Eğer iatanan 1niye eğer açıklamada, i == 0dönüşü true?


83
Çocuklar, bu bir yazım hatası sorusu değil. OP beri ise ifadesi bu kodla girilir nedenini öğrenmek ister iolarak ayarlanır 1.
NathanOliver

24
Yoksa sonucunu veriyor 1 && i == 0mu?
JVApen

4
Yeni başlayanlar için öneri: Böyle bir "gelişmiş" dil yapısı kullanmamalıdırlar. Değişkeni ayrı olarak atamanız yeterlidir. Bu aynı zamanda sıralama noktasıyla ilgili olası sorunları da önleyecektir. Pratik koddaki bu tür kodlar genellikle kötü görünür.
user202729

1
Bu bir röportaj sorusu ile
sonuçlanmak zorunda

Yanıtlar:


391

Bu operatörün önceliği ile ilgilidir .

if (i = 1 && i == 0)

değil

if ((i = 1) && (i == 0))

Her iki yüzünden &&ve ==daha yüksek önceliğe sahiptir =. Gerçekten işe yaradığı şey

if (i = (1 && (i == 0)))

bunlardan sonucu atar 1 && (i == 0)için i. Yani, eğer iat başlar 0sonra i == 0ise true, yani 1 && truebir true(veya 1), ardından iayarlı alır 1. Sonra 1doğru olduğundan if bloğunu girip atadığınız değeri yazdırırsınız i.


2
@ JörgWMittag Çok güzel. Seni parantez kullanmaya zorluyor.
NathanOliver

Temel olarak, i = !i; if (i)düzgün yazılmış
Cacahuete Frito

@NathanOliver: Fortress, birçok şeyi doğru yapan oldukça havalı bir dildi. (Baş tasarımcı Guy L.Steele'ydi, bu yüzden orada sürpriz olmadı.) Ne yazık ki, DARPA finansmanının son turu için alınmadı ve daha sonra Oracle tarafından güvendi.
Jörg W Mittag

6
Doğal olarak, derleyiciden bir modicum uyarı istemek bu hatayı tespit ederdi,
Deduplicator

4
Ints ve boolean'ın eşdeğer olduğunu varsaymayan herhangi bir dil de bunu alacaktır.
rghome

16

Kodunuzun aslında şu şekilde olduğunu varsayarsak:

#include <iostream>
using namespace std;

int main()  {
    int i = 0;
    if (i = 1 && i == 0) {
        cout << i;
    }
}

Sonra bu:

if (i = 1 && i == 0) {

olarak değerlendirir

 if (i = (1 && i == 0)) {

ve böylece iolarak ayarlanır 1.


39
Ekstra kod gerçekten gerekli miydi? Aksi halde çalışmayacağı için durumun bu olacağı oldukça açık görünüyor.
Modelmat

13
Sadece gereksiz ekstra kod değil. Cevap, operatörün önceliğini açıkça açıklayamıyor.
Francisco Zarabozo

34
Nitpick trenindeyken ... Anladım using namespace std!
Mateen Ulhaq

8
Ekstra kod var - ama yine de yanlış kod değil. Ve cevap hala doğru. Tabii ki, operatör önceliğini açıklamaz. Ancak birileri, açıkça aşağı oylama yerine eklenmesini önerebilir!
B Charles H

14
Vay canına, -4 sert, bu soruya doğru cevap verirken, belki de optimal değil. Diğer yanıt kadar operatör önceliğinde genişlemez, ancak kod bağlamında bu konuda yeterli olduğunu söyler, böylece daha =önce gelenlerin &&sorunu görebilmesini sağlar. Ayrıca, evet, genişleme yabancı, ama bence o kadar önemli değil. Böyle küçük farklılıkların insanların 151 ila -4 oy vermesine neden olduğuna inanamıyorum.
JoL

-4

Bu, sağdan sola kuralların ayrıştırılmasıyla ilgilidir. Örneğin y = x + 5.
Tüm alt ifadeler önem taşır. Eşit öneme sahip iki ifade sağdan sola değerlendirilir. Önce && ifade tarafı, ardından LHS yapılır.

Bana mantıklı geldi.


1
İlişkiliğin ("sağdan sola kurallar") bununla hiçbir ilgisi yoktur. Bu öncelikle ilgilidir ("önem") ve kullanılan operatörler eşit önceliğe sahip değildir .
Yörüngedeki Hafiflik Yarışları

-4

Asıl cevap:

  1. Derleyici, doğru olarak değerlendirilen "i == 0" a öncelik verir .
  2. Daha sonra i = 1'i TRUE veya FALSE olarak değerlendirir ve derlenmiş atama işleçleri hiçbir zaman başarısız olmaz (aksi takdirde derlemezler), true olarak da değerlendirilir.
  3. Her iki ifade de doğru olarak değerlendirildiğinden ve TRUE && TRUE, TRUE olarak değerlendirdiğinden, if ifadesi TRUE olarak değerlendirilir.

Kanıt olarak, girdiğiniz kod için derleyicinizin asm çıkışına bakın (tüm yorumlar benimdir):

mov     dword ptr [rbp - 8], 0    ; i = 0;
cmp     dword ptr [rbp - 8], 0    ; i == 0?
sete    al                        ; TRUE (=1)
mov     cl, al
and     cl, 1                     ; = operator always TRUE
movzx   edx, cl
mov     dword ptr [rbp - 8], edx  ; set i=TRUE;
test    al, 1                     ; al never changed,
                                  ; so final ans is TRUE

Yukarıdaki asm çıktısı CLANG'dan geliyordu, ancak baktığım diğer tüm derleyiciler benzer çıktı verdi. Bu, o sitedeki tüm derleyiciler için, ister saf C veya C ++ derleyicileri olsun, hepsi derleyicinin modunu değiştirmek için herhangi bir pragmasız (bu varsayılan olarak C ++ derleyicileri için C ++)

Derleyicinizin aslında i = 1 değerini ayarlamadığını, ancak i = TRUE değerini (sıfır olmayan tamsayı değeri olmayan 32 bit anlamına gelir) ayarladığını unutmayın. Çünkü && operatörü yalnızca bir ifadenin DOĞRU veya YANLIŞ olup olmadığını değerlendirir ve ardından sonuçları bu sonuca göre ayarlar. Kanıt olarak, i = 1'i i = 2 olarak değiştirmeyi deneyin ve hiçbir şeyin değişmeyeceğini kendiniz görebilirsiniz. Compiler Explorer'da herhangi bir çevrimiçi derleyiciyi kullanarak kendiniz görün


1
1) Bu soru C ++ ile etiketlendiğinde dokümanlar C operatörü önceliğine bağlantı verir. İki farklı dil. 2a) i = 1bir ödev [denklik değil] operatörüdür; 2b) if (i = 0)Hem C hem de C ++ 'da yanlış durumu değerlendireceğini garanti edebilirim .
TrebledJ

1
and cl, 1 ; = operator always TRUE<< yanılıyorsam beni düzeltin, ama burada atama görmüyorum. 1 &&İfadenin bir kısmını temsil eder . Yani bu cevap temel olarak değerlendiriyor false.
1919'da

"Bu soru C ++ ile etiketlendiğinde dokümanlar C operatörü önceliğine bağlanır. İki farklı dil" - ve C ile C ++ operatörü önceliğini karşılaştırdığınızda, ikisi arasındaki fark nedir? Şaşırtıcı olmayan bu konuyla ilgili olarak aynı önceliğe sahipler, C ++ olarak C'nin doğrudan bir türevidir (veya bunu söylemenin başka bir yolu, C, C ++ dilinin bir alt kümesidir, bu yüzden elbette öncelik de dahil olmak üzere birçok ortak nokta). Kafa karıştırıcı olması durumunda postamı yine de düzeltirim.
ar18

"Eğer yanılıyorsam beni düzeltin ama burada görev göremiyorum" - O zaman seni düzeltmeme izin ver! 1, herhangi bir test veya hesaplamanın sonucu değil, derhal bir değerdir. Buna "varsayılan TRUE" değeri denir. Gerçekleşen tek test i == 0 ifadesi içindir, yani - "cmp dword ptr [rbp - 8], 0". Sadece "movzx edx, 1" yazsaydı doğru olurdu. Benden önceki tüm yayınlara göre, iki karşılaştırma olmalı, ancak gerçek hayatta sadece bir tane var ve HER ana derleyicinin asm çıktısı bu yayınların tamamen yanlış olduğunu kanıtlıyor.
ar18

2
Önceliği yanlış anlamanın yanı sıra (NathanOliver'ın doğru ayrıştırma için cevabına da bakınız), atama operatörünün her zaman TRUE olarak değerlendirdiğini iddia etmek yanlış iddiada bulunuyorsunuz. Deneyin if ( i = 0 ) { print something }. Ayrıca cevabınız kendisiyle çelişiyor; başlangıçta daha i=1önce değerlendirildiğini söyler &&ve sonunda ibunun &&operatörün sonucuna ayarlandığını söylersin .
MM
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.