อะไรที่ทำให้นักพัฒนา C อยากรู้อยากเห็นถ้า "i ++ == ++ i"? [ปิด]


15

เพียงสังเกตแบบสุ่มดูเหมือนว่าใน StackOverflow.com มีคำถามเกี่ยวกับว่า "++ i == i ++" คำถามนั้นถูกถามตลอดเวลา แต่ฉันคิดว่าฉันเห็นมันถามประมาณ 6 หรือ 7 ครั้งใน 2 เดือนที่ผ่านมา

ฉันแค่สงสัยว่าทำไมนักพัฒนา C ถึงสนใจ? มีแนวคิด / คำถามเดียวกันสำหรับ C # และ Java devs เช่นกัน แต่ฉันคิดว่าฉันเห็นคำถามที่เกี่ยวข้องกับ C # เพียงรายการเดียว

เป็นเพราะตัวอย่างมากมายใช้ ++ i เป็นเพราะมีหนังสือหรือแบบฝึกหัดยอดนิยมบ้างไหม? เป็นเพราะผู้พัฒนา C รักที่จะยัดเยียดให้มากที่สุดเท่าที่จะทำได้ในบรรทัดเดียวสำหรับ 'ประสิทธิภาพ' / 'ประสิทธิภาพ' และดังนั้นจึงพบโครงสร้าง 'แปลก' โดยใช้ตัวดำเนินการ ++ บ่อยขึ้นหรือไม่


23
(สำหรับฉันในฐานะ C # dev, i ++ และ ++ ฉันเท่ากันฉันรู้ว่ามันไม่ใช่ แต่ถ้าฉันเขียนโค้ดที่ขึ้นอยู่กับความแตกต่างฉันอยากจะ refactor ให้อ่านง่ายขึ้นและคาดหวังว่าคอมไพเลอร์และ JITter จะดูแล ของมัน แต่เป็น C # dev ฉันไม่ได้พยายามที่จะบันทึกหนึ่งหรือสองรอบนาฬิกาเพราะฉันค่อนข้างไม่มีประสิทธิภาพอยู่แล้ว)
Michael Stum

1
ในฐานะนักเขียนโปรแกรมเราชอบเล่นด้วยเลขคณิตตรรกะและอยากรู้อยากเห็นว่าสิ่งต่าง ๆ ทำงานอย่างไร ฉันคิดว่านั่นเป็นเหตุผลใหญ่ที่เราไม่มีใครชอบคำถามดังกล่าว มันอาจจะไม่ใช่คุณสมบัติที่น่ากลัว แต่ก็น่าสนใจ! ไม่ใช่เหตุผลที่เราเป็นโปรแกรมเมอร์ตั้งแต่แรก?!
Chani

2
คุณหมายถึงการแสดงออกอย่างแท้จริง++i == i++หรือโดยทั่วไปเกี่ยวกับความแตกต่างในความหมายระหว่าง++iและi++?
Keith Thompson

คำตอบ:


30

ฉันสงสัยว่าอย่างน้อยส่วนหนึ่งของมันง่ายกว่าเล็กน้อย: ถึงตอนนี้เรายังเห็นคำถามมากมายที่เริ่มตั้งแต่ต้นปีการศึกษาและพวกเขาก็ค่อย ๆ ลดลงตลอดทั้งปี

เช่นนี้ฉันคิดว่ามันยุติธรรมที่จะเดาว่ามีเพียงไม่กี่คนเท่านั้นที่เป็นผลมาจากชั้นเรียนที่ครูพูดถึงอย่างน้อยก็นิดหน่อย แต่ก็ไม่ได้อธิบายประเด็นของเขาได้ดี (บ่อยครั้งที่ไม่ เพราะเขาไม่เข้าใจตัวเองจริงๆ) โดยเฉพาะอย่างยิ่งจากคนที่ดูเหมือนจะถามคำถามเหล่านี้มีเพียงไม่กี่คนที่ใช้การเข้ารหัสจริง


14
นี่ไม่ใช่สิ่งที่ตรงกันข้ามกับ Eternal September ใช่ไหม นิรันดร์กันยายนคือเมื่อ AOL เริ่มเสนอการเข้าถึง Usenet ให้กับลูกค้าของพวกเขาทำให้ดูเหมือนว่ากันยายน (เดือนที่นักเรียนใหม่เริ่มเข้าโรงเรียนตามเนื้อผ้าจู่โจมกระดานเป็นมือใหม่) ตลอดทั้งปี
nlawalker

มันเป็นทฤษฎีที่น่าสนใจ แต่บางทีมันอาจไม่ใช่ความผิดของครูเสมอไปถ้ามีคนไม่เข้าใจเนื้อหา: นักเรียนอาจจะ (1) ไม่สนใจพอในชั้นเรียนและ (2) ขี้เกียจเกินไปที่จะหาคำตอบใน stackoverflow ก่อน ถามคำถามเดียวกันอีกครั้ง
จอร์โจ

12

เพราะโปรแกรมเมอร์ C ต้องเข้าใจคำสั่งของการดำเนินการ นักพัฒนา C # ไม่จำเป็นต้องใช้ตัวดำเนินการระดับบิต (&, |, ~) หรือตัวดำเนินการนำหน้าเนื่องจากเรามักจะกังวลเรื่องอื่นมากกว่า อย่างไรก็ตามสิ่งที่เราไม่ได้ตระหนักคือเราควรรู้ว่าผู้ประกอบการที่เราใช้ในชีวิตประจำวันทำอย่างไรและจะใช้งานอย่างไรให้ถูกต้อง พวกเราส่วนใหญ่หลีกเลี่ยงสถานที่ที่อาจเป็นปัญหา

จากด้านบนของหัวผลลัพธ์ของตัวอย่างนี้คืออะไร

    double x = 5.5;
    Console.WriteLine(x++);
    x = 5.5;
    Console.WriteLine(++x);

ฉันจะบอกว่าจำนวนมากของซีซั่น C # devs ไม่รู้ว่าเอาต์พุตของคอนโซลคืออะไร


3
+1 การทราบความแตกต่างระหว่างตัวดำเนินการเพิ่ม / ลดก่อนและหลังการแก้ไขนั้นมีค่าสำหรับสถานการณ์เช่นนี้
Maulrus

4
ฉันเห็นประเด็นแล้วและฉันก็ไม่รู้เหมือนกันว่าเอาท์พุท (ฉันเชื่อว่ามันเป็น 5.5 และ 6.5 แต่ฉันไม่แน่ใจ) และสำหรับฉันมันไม่สำคัญว่าฉันจะปรับให้เป็น x ++; Console.WriteLine (x); ทันที ฉันไม่ได้งมงายทั้งหมด แต่ฉันคิดว่ามันเป็นกลิ่นรหัสขนาดใหญ่ที่มีการใช้งานเป็นศูนย์
Michael Stum

9
คำตอบสำหรับคำถามไม่มีส่วนเกี่ยวข้องกับคำสั่งของการดำเนินการหรือความแตกต่างระหว่างคำนำหน้าและการเพิ่มคำนำหน้า มันเป็นเรื่องของพฤติกรรมที่กำหนดและไม่ได้กำหนด
David Thornley

2
ฉันพบสิ่งนี้วันนี้ if (myList[i++] == item)สิ่งที่ชอบ ฉลาด. ฉันพบว่ากำลังมองหาแหล่งที่มาของข้อยกเว้น IndexOutOfRange ... แท้จริงแล้ว "ฉลาดมาก"
rmac

7
ฉันคิดว่ามันเป็น 5.5 และ 6.5 แต่ฉันไม่เคยเห็น++ใช้ในการลอยมาก่อนและฉันต้องบอกว่ามันไม่เหมาะสม คนทำอย่างนั้นหรือ (ฉันต้องการ+= 1)
Bart van Heukelom

8

ฉันคิดว่านี่ชัดเจน ใน C #, สำหรับint i, i++ == ++iเสมอในขณะที่เป็นเท็จ++i == i++เป็นจริงเสมอน่าเชื่อถือและทุกคนที่สนใจสามารถหานี้ออกได้อย่างง่ายดายเพียงแค่การเรียนรู้กฎของ C # (หรืออันที่จริงโดยเพียงแค่ใช้มัน)

ใน C และ C ++ ในทางกลับกันมันใกล้เคียงกับ undefined เพราะมันขึ้นอยู่กับคอมไพเลอร์สภาพแวดล้อมในการดำเนินการแพลตฟอร์ม ฯลฯ ดังนั้นจึงเป็นคำถามที่ตอบยากกว่าดังนั้นผู้คนจำนวนมากจึงถาม


+1 - แต่ไม่ใช่คำถามที่ยากกว่าที่จะตอบ "undefined" เป็นหนึ่งคำ ทุกสิ่ง "ขึ้นอยู่กับ ... " คือสิ่งที่คนส่วนใหญ่ไม่ต้องกังวล แม้ว่าคุณจะเขียนเฉพาะแพลตฟอร์มเดียวคุณควรใช้สำนวนปกติสำหรับภาษาโดยรวมและการใช้ตัวดำเนินการ pre-increment และ post-increment ส่วนใหญ่เป็นส่วนหนึ่งของสำนวนทั่วไป
Steve314

+1: นี่เป็นคำตอบที่ถามจริง (นั่นคือคุณไม่ได้อ่านระหว่างบรรทัด)
Thomas Eding

7

มันเป็นคำถามยอดนิยมเพราะมันเป็นคำถามที่หลอกลวง มันไม่ได้กำหนด

ลิงค์ด้านบนไปที่คำถามที่พบบ่อยในหน้าแรกของ Bjarnes Stroustrup ซึ่งตอบคำถามนี้โดยเฉพาะและอธิบายว่าทำไมการสร้างนี้จึงไม่ได้กำหนด สิ่งที่กล่าวคือ:

โดยทั่วไปใน C และ C ++ ถ้าคุณอ่านตัวแปรสองครั้งในนิพจน์ที่คุณเขียนมันผลลัพธ์จะไม่ได้กำหนด

การมีลำดับของการประเมินผลที่ไม่ได้กำหนดจะอ้างว่าให้รหัสที่มีประสิทธิภาพดีกว่า


5

เป็นไปได้มากเพราะใน C มันสำคัญมากถ้าคุณเขียนi++หรือ++iเมื่อคุณกำลังใช้เลขคณิตของตัวชี้ การเพิ่มiก่อนหรือหลังการปฏิบัติการอาจมีความสำคัญ ฉันจะให้คุณตัวอย่าง แต่ครั้งสุดท้ายที่ฉันเขียน C คือ 10 ปีที่แล้ว ...

ใน C # ฉันไม่เคยเจอสถานการณ์ที่จะต้องให้ฉันคิดi++หรือ++iเพราะ AFAIK สำหรับลูปสำหรับ / ในขณะที่มันไม่สำคัญ


3
ยังคงเป็นสิ่งสำคัญที่จะต้องเข้าใจความแตกต่างใน C # - เพียงเพราะคุณดูเหมือนจะใช้พวกเขาในสำหรับ / แต่ละลูปไม่ได้หมายความว่าเป็นสถานที่เดียวที่คุณจะพบพวกเขา
STW

จริงทั้งหมดที่
Mladen Prajdic

3
สิ่งนี้ไม่เกี่ยวข้องกับคำถาม คำถามไม่ได้เกี่ยวกับความแตกต่างระหว่างi++และ++iแต่รวมไว้ในนิพจน์เดียวกัน
David Thornley

@ David คำถามคือทำไมโปรแกรมเมอร์ C อยากรู้เกี่ยวกับมัน คำตอบ (มันเรื่องใน C ไม่มากใน C #) มีความเกี่ยวข้องอย่างสมบูรณ์".
Florian F

2

ไม่กี่ปีที่ผ่านมาฉันอ่านว่าตัวดำเนินการเหล่านี้ถือว่าอันตรายดังนั้นฉันจึงพยายามขุดข้อมูลเพิ่มเติม ถ้า stackoverflow เกิดขึ้นในตอนนั้นฉันก็จะถามที่นั่น

ตอนนี้เป็นเพราะคนที่บิดเบี้ยวเขียนลูปเช่น

while( [something] )
{
  a[++j] = ++j;
}

แม้ตอนนี้ฉันยังไม่แน่ใจเกี่ยวกับสิ่งที่จะเกิดขึ้น แต่ก็ชัดเจนสำหรับฉันที่หลาย ++ [var] ในบรรทัดเดียวกันกำลังถามปัญหา


2
การเพิ่มขึ้นมีพฤติกรรมที่ไม่ได้กำหนดซึ่งเป็นส่วนหนึ่งของการมอบหมายใน C
tzenes

7
การมอบหมายเช่นx = ++j;นี้ถูกกำหนดไว้อย่างดีใน C. ด้านบนนี้ไม่ได้ถูกกำหนดเนื่องจากjมีการแก้ไขสองครั้งโดยไม่มีจุดลำดับที่เข้ามาแทรกแซง
Matthew Flaschen

2

ด้วยเหตุผลสองประการ

การนำไปใช้ที่ถูกต้องของ ++ i คือการเพิ่ม i และจากนั้นส่งคืน การนำไปปฏิบัติที่ถูกต้องของ i ++ คือการบันทึกค่าปัจจุบันเพิ่มขึ้น i และคืนค่าที่บันทึกไว้ การรู้สิ่งเหล่านี้ไม่ได้เกิดขึ้นเนื่องจากคำพ้องความหมายเป็นสิ่งสำคัญ

คำถามก็จะกลายเป็นเมื่อรวบรวมใช้พวกเขาในขณะที่การประเมินการแสดงออกเช่นความเท่าเทียมกัน

หากการทดสอบความเสมอภาคเสร็จสิ้นก่อนผู้ประกอบการก่อนและหลังคุณจะต้องเขียนตรรกะที่แตกต่างกว่าถ้าด้านซ้ายมือ (lhs) และด้านขวามือ (rhs) ถูกประเมินก่อนจากนั้น ความเสมอภาค

มันคือทั้งหมดที่เกี่ยวกับลำดับของการดำเนินการและในทางกลับกันจะมีผลกับรหัสหนึ่งที่เขียน และไม่น่าแปลกใจมากนักไม่ใช่ทุกภาษาที่มีข้อตกลง

รายการการทดสอบพื้นฐานนี้ช่วยให้นักพัฒนาสามารถทดสอบเพื่อดูว่าสมมติฐานของพวกเขาถูกต้องเช่นเดียวกับถ้าการใช้งานจริงตรงกับข้อกำหนดภาษา

สิ่งนี้สามารถมีผลกระทบทุกชนิดเมื่อทำงานกับพอยน์เตอร์ลูปหรือค่าที่ส่งคืน


5
การทดสอบพื้นฐานเกี่ยวกับสิ่งนี้จะทำให้เข้าใจผิดเนื่องจากเป็นพฤติกรรมที่ไม่ได้กำหนด หากทำงานได้อย่างแม่นยำตามที่คุณคาดหวังในครั้งนี้จะไม่มีการรับประกันว่าในครั้งถัดไป
David Thornley

คุณได้ตอบคำถามที่ผิด คุณควรตอบว่าทำไมโปรแกรมเมอร์ C ถึงสงสัย
Hugo

พาราที่สองของคุณล่ะค่ะที่ไม่ถูกต้อง (ก่อนที่จะ C ++ 11 อย่างน้อย): ลักษณะการทำงานของ++iคือการใช้ค่าi+1และที่จุดในบางครั้งอาจจะก่อนหรือหลังนั้น iแต่ก่อนที่จะจุดลำดับถัดไปเพิ่มขึ้น
MM

@ MattMcNabb - คุณช่วยชี้ให้ฉันดูสเปคสำหรับสิ่งนั้นได้ไหมฉันอยากรู้อยากเห็นถ้าสิ่งต่าง ๆ มีการเปลี่ยนแปลงในการนำไปใช้ ย้อนกลับไปในวันที่ C ทำแผนที่กับชุดประกอบ PDP, ++ ฉันฉีดคำสั่ง INC ในขณะที่รุ่นต่อท้ายต้องคัดลอกค่าในการลงทะเบียนเพื่อใช้คำสั่งหลังจากการเพิ่มขึ้น อะไรเป็นสิ่งจำเป็นสำหรับการเปลี่ยนแปลงที่คุณอธิบาย?
Walt Stoneburner

2

ฉันคิดว่ามันเป็นวัฒนธรรมที่น่าตกใจ

ดังที่ได้กล่าวแล้วพฤติกรรมของการแสดงออกใน C หรือ C ++ นั้นไม่สามารถกำหนดได้เนื่องจากลำดับของการดำเนินการของการเพิ่มภายหลัง ฯลฯ ไม่ได้ถูกกำหนดอย่างเคร่งครัด พฤติกรรมที่ไม่ได้กำหนดเป็นเรื่องธรรมดาใน C และแน่นอนว่ามีการนำเข้าสู่ C ++ มากมาย

สำหรับคนที่เคยเขียนโปรแกรมในภาษาอื่น - ใครบางคนที่หยิบยกแนวคิดว่าภาษาโปรแกรมควรจะแม่นยำและคอมพิวเตอร์ควรจะทำสิ่งที่พวกเขาบอกให้ทำ ... ดีมันเป็นเรื่องที่น่าตกใจ ค้นพบว่า C มีเจตนาคลุมเครือเกี่ยวกับบางสิ่ง


C เป็นอย่างนี้เพราะมันถูกออกแบบมาเพื่อรองรับแพลตฟอร์มมากกว่าที่มีอยู่อย่างมากมายแม้กระทั่งเมื่อมีการกำหนด C # รวมถึงแพลตฟอร์มฝังตัวที่แปลกประหลาดหรือเมนเฟรมที่คุณนึกออก ในทางกลับกัน C # จะทำงานบน ... x86 และ 360 หรือไม่ อาจ ARM ด้วยหรือไม่ ไม่มีอะไรอีกแล้ว. นั่นเป็นสาเหตุที่ C # สามารถนิยามได้มากขึ้น
DeadMG

++ เช่นกัน C ไม่ได้สร้างขึ้นครั้งแรกใน PDP-11 ใช่หรือไม่ มีคำแนะนำการเพิ่มอัตโนมัติที่ไหน C ต้องการที่จะ "ใกล้กับเครื่อง" เพื่อให้สามารถใช้ประโยชน์จากชุดคำสั่ง
Mike Dunlavey

@MikeDunlavey: ไม่, C ++และ--ตัวดำเนินการไม่ได้อยู่บนพื้นฐานของ PDP-11 ซึ่งไม่มีอยู่เมื่อตัวดำเนินการเหล่านั้นถูกนำมาใช้ในภาษาบรรพบุรุษของ C โปรดดูcm.bell-labs.com/who/dmr/chist.htmlและ ค้นหา "การเพิ่มอัตโนมัติ"
Keith Thompson

1

บางทีอาจเป็นเพราะผู้พัฒนา C ใช้การเพิ่ม ++ บ่อยครั้งมากขึ้นโดยดูว่า C ไม่มีคำสั่ง "foreach" หรือคำสั่งที่คล้ายกันในการทำซ้ำผ่านอาร์เรย์ โอ้และแน่นอนตัวชี้ทางคณิตศาสตร์ดังกล่าวก่อนหน้านี้!


1
จุดดีลืมว่า foreach เป็นแนวคิดที่ค่อนข้างทันสมัย
Michael Stum

-1

ความแตกต่างระหว่างทั้งสองส่วน: การโพสต์และการพรีเมนต์ล่วงหน้ากำลังทำงานในลักษณะที่โค้ดสองชิ้นนี้ควรทำงานในทุกภาษา นี้ไม่ได้ขึ้นอยู่กับภาษา !!!

++i

นี่คือการเพิ่มขึ้นก่อน ส่วนของรหัสนี้จะเพิ่มมูลค่าiก่อนที่จะส่งค่าไปยังบรรทัดที่ใช้

i++

นี่คือการเพิ่มโพสต์ ส่วนของรหัสนี้จะคืนค่าiก่อนที่จะเพิ่มมูลค่าของiในบรรทัดที่มีการใช้

ในอีกตัวอย่างเล็ก ๆ :

int main(void)
{
  int i = 0; 
  int result; 
  result = 10 + ++i; 
  printf("%d \n", result); // = 11 

  int j = 0; 
  result = 10 + j++; 
  printf("%d \n", result);// = 10
  return 0;
}

รหัสนี้รวบรวมกับผลลัพธ์บนแผ่นจดบันทึก

สิ่งนี้เกี่ยวข้องกับการใช้งานภายในของตัวดำเนินการโอเวอร์โหลด

++i เพิ่มมูลค่าโดยตรง (และเร็วขึ้นเล็กน้อย)

i++ก่อนสร้างสำเนาที่ถูกส่งกลับไปยังสถานที่ที่จำเป็นและหลังจากนั้นค่าเดิมของiตัวแปรจะเพิ่มขึ้นโดยหนึ่ง

ฉันหวังว่านี่ชัดเจนแล้ว


แต่นี่ไม่ใช่คำถามจริง: ทำไมนักพัฒนา C ถามถึงเรื่องนี้มากกว่าคนอื่น OP เข้าใจผู้ปฏิบัติงาน
Martijn Pieters

คำตอบนี้ไม่ถูกต้องตามข้อเท็จจริงแล้ว ++iไม่เร็วและi++ไม่สร้างสำเนา นอกจากนี้ยัง++iมีพฤติกรรมที่แตกต่างกันเล็กน้อยใน C กว่าใน C ++ โดยไม่ต้องพูดถึงภาษาอื่น
MM
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.