Apa yang membuat pengembang C sangat penasaran jika “i ++ == ++ i”? [Tutup]

15

Hanya pengamatan acak, tampaknya di StackOverflow.com, ada pertanyaan tentang apakah "++ i == i ++". Pertanyaan itu selalu ditanyakan, saya pikir saya melihatnya 6 atau 7 kali dalam 2 bulan terakhir.

Saya hanya ingin tahu mengapa pengembang C sangat tertarik pada itu? Konsep / pertanyaan yang sama ada untuk C # dan Java devs juga, tapi saya pikir saya hanya melihat satu pertanyaan terkait C #.

Apakah karena begitu banyak contoh menggunakan ++ i? Apakah karena ada beberapa buku atau tutorial populer? Apakah karena pengembang C hanya suka menjejalkan sebanyak mungkin ke dalam satu baris untuk 'efisiensi' / 'kinerja' dan oleh karena itu menemukan konstruksi 'aneh' menggunakan operator ++ lebih sering?

Michael Stum
sumber
23
(Bagi saya sebagai seorang C # dev, i ++ dan ++ i adalah sama. Saya tahu mereka tidak, tetapi jika saya menulis kode yang tergantung pada perbedaan saya lebih suka refactor agar lebih mudah dibaca dan mengharapkan kompiler dan JITter untuk berhati-hati itu, tetapi sebagai C # dev saya tidak mencoba untuk menyimpan satu atau dua siklus jam karena saya sudah relatif tidak efisien pula)
Michael Stum
1
sebagai programmer pemula kita suka bermain dengan aritmatika, logika, dan ingin tahu bagaimana hal-hal bekerja. Saya pikir itu alasan utama kita noobs suka pertanyaan seperti itu. itu mungkin bukan fitur yang memalukan, tapi itu pasti menarik! Bukankah itu alasan kami menjadi programmer sejak awal ?!
Chani
2
Apakah Anda benar-benar merujuk pada ungkapan ++i == i++, atau lebih umum tentang perbedaan makna antara ++idan i++?
Keith Thompson

Jawaban:

30

Saya menduga bahwa setidaknya sebagian darinya sedikit lebih sederhana: bahkan sekarang, kita melihat banyak pertanyaan seperti ini mulai sekitar awal tahun sekolah, dan mereka berangsur-angsur berkurang sepanjang tahun.

Dengan demikian, saya pikir wajar untuk menebak bahwa beberapa dari mereka hanyalah hasil dari kelas di mana guru berbicara setidaknya sedikit tentang hal itu, tetapi tidak menjelaskan maksudnya dengan baik (sesering mungkin tidak karena dia sendiri tidak terlalu mengerti mereka). Terutama berdasarkan pada orang-orang yang tampaknya mengajukan pertanyaan-pertanyaan ini, sedikit yang didasarkan pada pengkodean aktual.

Jerry Coffin
sumber
14
Bukankah ini kebalikan dari September Abadi? September yang kekal adalah ketika AOL mulai menawarkan akses Usenet kepada pelanggan mereka, menjadikannya seperti bulan September (bulan ketika siswa baru mulai sekolah secara tradisional membombardir papan sebagai pemula) sepanjang tahun.
nlawalker
Ini adalah teori yang menarik tetapi mungkin itu tidak selalu kesalahan guru jika seseorang tidak memahami materi: mungkin para siswa (1) tidak memberikan perhatian yang cukup selama kelas dan (2) terlalu malas untuk mencari jawaban pada stackoverflow sebelumnya menanyakan pertanyaan yang sama lagi.
Giorgio
12

Karena programmer C HARUS memahami urutan operasi. Pengembang C # tidak perlu menggunakan operator bitwise (&, |, ~) atau operator awalan karena kami biasanya lebih khawatir tentang hal-hal lain. Namun, apa yang tidak kita sadari oleh C # dev adalah bahwa kita harus tahu apa yang dilakukan oleh operator yang kita gunakan setiap hari dan bagaimana menggunakannya dengan benar. Sebagian besar dari kita hanya menghindari tempat-tempat di mana ini mungkin menjadi masalah.

Dari atas kepala Anda, apa output dari potongan ini?

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

Saya akan mengatakan sejumlah besar C # devs berpengalaman tidak tahu apa output ke Konsol.

Nate Noonen
sumber
3
+1. Mengetahui perbedaan antara operator kenaikan / penurunan sebelum dan sesudah perbaikan sangat berharga untuk situasi seperti ini.
Maulrus
4
Saya agak mengerti maksudnya dan saya tidak akan tahu outputnya (saya percaya ini 5,5 dan 6,5, tapi saya tidak yakin), dan bagi saya itu tidak masalah karena saya akan mengubahnya menjadi x ++; Console.WriteLine (x); segera. Namun saya tidak sepenuhnya bodoh, saya hanya berpikir itu bau kode besar dengan nol kegunaan.
Michael Stum
8
Jawaban atas pertanyaan itu tidak ada hubungannya dengan urutan operasi, atau perbedaan antara kenaikan awalan dan kenaikan akhir. Ini masalah perilaku yang didefinisikan dan tidak terdefinisi.
David Thornley
2
Saya menemukan ini hari ini. Sesuatu seperti if (myList[i++] == item). Pintar. Saya menemukannya mencari sumber pengecualian IndexOutOfRange ... Memang, sangat "pintar".
rmac
6
Saya pikir ini 5,5 dan 6,5, tetapi saya belum pernah melihat ++digunakan pada pelampung sebelumnya, dan saya harus mengatakan itu tidak merasa sangat tepat. Apakah orang melakukannya? (Saya lebih suka += 1)
Bart van Heukelom
8

Saya pikir ini sudah jelas. Dalam C #, untuk suatu int i, i++ == ++iselalu salah sementara ++i == i++selalu benar, andal, dan semua orang yang tertarik dapat mengetahui ini dengan mudah hanya dengan mempelajari aturan C # (atau memang dengan hanya menjalankannya).

Di C dan C ++, di sisi lain, itu hampir tidak terdefinisi karena tergantung pada kompiler, lingkungan eksekusi, platform, dll., Jadi itu adalah pertanyaan yang jauh lebih sulit untuk dijawab, jadi banyak orang bertanya.

Timwi
sumber
+1 - tetapi sebenarnya bukan pertanyaan yang lebih sulit untuk dijawab. "tidak terdefinisi" adalah satu kata. Semua hal "itu tergantung pada ..." adalah hal-hal yang kebanyakan orang tidak khawatirkan. Bahkan jika Anda hanya menulis untuk satu platform tertentu, Anda harus menggunakan idiom normal untuk bahasa secara keseluruhan, dan sebagian besar penggunaan operator pra-kenaikan dan pasca-kenaikan adalah bagian dari beberapa idiom umum.
Steve314
+1: Ini sebenarnya menjawab pertanyaan yang diajukan (yaitu, Anda tidak membaca yang tersirat).
Thomas Eding
7

Ini pertanyaan populer karena ini pertanyaan jebakan. Itu tidak terdefinisi .

Tautan di atas menuju ke FAQ tentang beranda Bjarnes Stroustrup, yang membahas pertanyaan ini secara khusus, dan menjelaskan mengapa konstruk ini tidak ditentukan. Apa yang dikatakannya adalah:

Pada dasarnya, dalam C dan C ++, jika Anda membaca variabel dua kali dalam ekspresi di mana Anda juga menulisnya, hasilnya tidak terdefinisi.

Memiliki urutan evaluasi yang tidak terdefinisi diklaim menghasilkan kode berkinerja lebih baik.

pengguna16764
sumber
5

Kemungkinan besar karena dalam C, itu sangat penting jika Anda menulis i++atau ++iketika Anda melakukan aritmatika pointer. Di sana, peningkatan isebelum atau setelah operasi bisa menjadi sangat penting. Saya akan memberi Anda contoh tetapi terakhir kali saya menulis C adalah 10 tahun yang lalu ...

Dalam C #, saya tidak pernah menemukan situasi yang mengharuskan saya untuk memikirkan i++atau ++ikarena AFAIK, untuk loop sementara, itu tidak masalah.

Mladen Prajdic
sumber
3
masih penting untuk memahami perbedaan dalam C # - hanya karena Anda tampaknya hanya menggunakannya untuk / setiap loop tidak berarti itu satu-satunya tempat Anda akan menemukannya
STW
sepenuhnya benar itu.
Mladen Prajdic
3
Ini tidak relevan dengan pertanyaan. Pertanyaannya bukan tentang perbedaan antara i++dan ++i, tetapi menggabungkan mereka dalam ekspresi yang sama.
David Thornley
@ David Pertanyaannya adalah mengapa programmer C ingin tahu tentang hal itu. Jawabannya (itu penting di C, tidak begitu banyak di C #) sepenuhnya relevan ".
Florian F
2

Beberapa tahun yang lalu saya membaca bahwa operator ini dianggap berbahaya sehingga saya mencoba menggali lebih banyak informasi tentangnya. Jika stackoverflow sudah pada saat itu, saya akan bertanya di sana.

Sekarang karena beberapa orang yang bengkok menulis loop seperti

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

Bahkan sekarang, saya tidak terlalu yakin tentang apa yang akan / harus terjadi, tetapi cukup jelas bagi saya bahwa banyak ++ [var] pada baris yang sama meminta masalah.

Eric
sumber
2
Penambahan memiliki perilaku yang tidak terdefinisi sebagai bagian dari penugasan di C
tzenes
7
Tugas seperti x = ++j;didefinisikan dengan baik dalam C. Di atas tidak terdefinisi karena jdimodifikasi dua kali tanpa titik urutan intervensi.
Matthew Flaschen
2

Dua alasan.

Implementasi yang benar dari ++ i adalah untuk meningkatkan i dan kemudian mengembalikannya. Implementasi i ++ yang benar adalah untuk menyimpan nilai saat ini, meningkatkan i, dan mengembalikan nilai yang disimpan. Mengetahui hal ini tidak dilaksanakan karena sinonim adalah penting.

Pertanyaannya kemudian menjadi kapan kompiler menerapkannya saat mengevaluasi ekspresi, seperti kesetaraan.

Jika tes persamaan dilakukan terlebih dahulu, maka operator sebelum dan sesudah kenaikan, Anda harus menulis logika yang berbeda daripada jika sisi kiri (lhs) dan sisi kanan (rhs) dievaluasi terlebih dahulu, kemudian kesetaraan.

Ini semua tentang urutan operasi, dan pada gilirannya mempengaruhi kode yang ditulis. Dan, tidak terlalu mengejutkan, tidak semua bahasa sepakat.

Daftar tes dasar ini memungkinkan pengembang untuk menguji untuk melihat apakah asumsi mereka benar, serta apakah implementasi yang sebenarnya sesuai dengan spesifikasi bahasa.

Ini dapat memiliki semua jenis dampak ketika bekerja dengan pointer, loop, atau nilai yang dikembalikan.

Walt Stoneburner
sumber
5
Tes dasar tentang ini akan menyesatkan, karena itu perilaku yang tidak terdefinisi. Jika itu berfungsi tepat seperti yang Anda harapkan saat ini, tidak ada jaminan itu akan lain kali.
David Thornley
Anda telah menjawab pertanyaan yang salah. Anda harus menjawab mengapa programmer C ingin tahu tentang hal itu.
Hugo
Para paragraf kedua Anda salah (setidaknya sebelum C ++ 11): perilaku ++iadalah menggunakan nilaii+1 dan pada titik waktu tertentu, mungkin sebelum atau setelah itu, tetapi sebelum titik urutan berikutnya, kenaikani .
MM
@MattMcNabb - Bisakah Anda mengarahkan saya ke spesifikasi untuk itu, saya ingin tahu jika ada perubahan dalam implementasi. Kembali pada hari-hari di mana C dipetakan dengan baik ke perakitan PDP, ++ saya menyuntikkan instruksi INC, sedangkan versi suffix harus menyalin nilai dalam register untuk menggunakan instruksi setelah kenaikan. Apa yang merupakan keharusan bagi perubahan yang Anda gambarkan?
Walt Stoneburner
2

Saya pikir ini adalah kejutan budaya.

Seperti yang telah ditunjukkan, perilaku ekspresi dalam C atau C ++ dapat tidak terdefinisi karena urutan eksekusi post-increments, dll tidak ditentukan secara ketat. Perilaku tidak terdefinisi cukup umum di C, dan tentu saja banyak yang diimpor ke C ++.

Untuk seseorang yang telah melakukan beberapa pemrograman dalam bahasa lain - seseorang yang telah mengambil gagasan bahwa bahasa pemrograman seharusnya tepat, dan bahwa komputer seharusnya melakukan apa yang diperintahkan untuk dilakukan ... yah, itu mengejutkan untuk temukan bahwa C sengaja disamarkan tentang beberapa hal.

Steve314
sumber
C adalah cara ini karena dirancang untuk mendukung platform yang jauh lebih banyak daripada yang ada saat C # didefinisikan, termasuk platform embedded atau mainframe paling aneh yang dapat Anda pikirkan. C #, di sisi lain, berjalan pada ... x86, dan 360? mungkin ARM juga? Tidak ada lagi. Itu sebabnya C # dapat mendefinisikan lebih banyak.
DeadMG
++ Juga, bukankah C pertama kali dibangun pada PDP-11? Di mana ada instruksi kenaikan-otomatis? C ingin "dekat dengan mesin" sehingga bisa memanfaatkan set instruksi yang bermanfaat.
Mike Dunlavey
@MikeDunlavey: Tidak, C ++dan --operator tidak didasarkan pada PDP-11, yang tidak ada ketika operator tersebut diperkenalkan dalam bahasa pendahulunya C B. Lihat cm.bell-labs.com/who/dmr/chist.html , dan cari "peningkatan otomatis".
Keith Thompson
1

Mungkin hanya bahwa pengembang C menggunakan kenaikan ++ lebih sering secara umum - melihat bagaimana C tidak memiliki "foreach" atau pernyataan serupa untuk beralih melalui array. Oh, dan tentu saja pointer aritmatika, seperti yang disebutkan sebelumnya!

Robert Roos
sumber
1
Poin baiknya, lupa bahwa pendahuluan adalah konsep yang relatif modern.
Michael Stum
-1

Perbedaan antara kedua bagian: post dan preincrement bekerja seperti cara kedua bagian kode ini berfungsi di setiap bahasa. INI BUKAN BAHWA TERGANTUNG BAHASA !!!

++i

Ini kenaikan pra. Sepotong kode ini pertama-tama akan meningkatkan nilai isebelum mengirim nilai ke baris di mana ia digunakan.

i++

Ini adalah kenaikan pos. Potongan kode ini akan mengembalikan nilai isebelum meningkatkan nilai ipada baris di mana ia digunakan.

Dalam contoh kecil lainnya:

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;
}

Kompilasi kode ini dengan hasil pada codepad.

Ini ada hubungannya dengan implementasi internal operator yang kelebihan beban.

++i meningkatkan nilai secara langsung (dan karena itu sedikit lebih cepat)

i++pertama membuat salinan yang dikembalikan ke tempat di mana diperlukan dan kemudian nilai asli dari ivariabel tersebut bertambah satu.

Saya harap ini jelas sekarang.

Krie999
sumber
Namun ini tidak menjawab pertanyaan aktual: mengapa pengembang C menanyakan hal ini lebih dari yang lain. OP memahami operator.
Martijn Pieters
Juga jawaban ini secara faktual salah. ++itidak lebih cepat, dan i++tidak membuat salinan. Lebih lanjut, ++iberperilaku sedikit berbeda dalam C daripada di C ++, apalagi di antara bahasa lain.
MM