Urutan pemanggilan fungsi (C++)

result= function_1()*function_2();

Saya menulis kode seperti di atas. Yang ingin saya ketahui adalah saat melakukan perkalian, fungsi manakah yang dipanggil terlebih dahulu? Hal ini karena fungsi yang dipanggil pertama kali dapat mempengaruhi hasil yang dikembalikan dari fungsi lainnya. Saya berasumsi function_1() dipanggil terlebih dahulu, dan ketika saya mencobanya saya melihat bahwa memang benar demikian. Namun, apakah selalu demikian? Apakah ini bergantung pada kompiler yang saya gunakan atau sistem yang saya gunakan?


person oicrisah    schedule 29.10.2014    source sumber


Jawaban (2)


Urutan evaluasi tidak ditentukan oleh standar C++ (atau C) (lihat jawaban dari Vlad). Jika function_1 atau function_2 Anda memiliki efek samping yang signifikan, ini mungkin berupa beberapa < a href="http://en.wikipedia.org/wiki/Unspecified_behavior" rel="nofollow noreferrer">perilaku yang tidak ditentukan yang harus benar-benar Anda hindari (seperti Anda harus menghindari perilaku tidak terdefinisi). Dan dalam beberapa kasus (fungsi sebaris dengan optimalisasi yang kuat) perhitungannya mungkin tercampur.

Pikirkan tentang kasus-kasus aneh seperti

 static int i;
 int function_1(void) { i++; return i; }
 int function_2(void) { i+=2; return 3*i+1; }

Ini mungkin spesifik untuk implementasi, dan mungkin bergantung pada kompiler sebenarnya dan tanda optimasi.

Anda harus membuat kode seolah-olah urutan pemanggilan fungsi benar-benar acak dan tidak dapat direproduksi (walaupun dalam praktiknya mungkin dapat direproduksi). Demikian pula, Anda tidak boleh mengharapkan urutan evaluasi argumen tertentu (misalnya di f(i++, ++j) Anda tidak tahu apakah i atau j telah bertambah terlebih dahulu), bahkan jika untuk kompiler tertentu urutan tersebut mungkin diperbaiki. Sekali lagi, Anda harus membayangkan urutan yang benar-benar acak dan tidak dapat direproduksi.

Seperti yang dikomentari oleh David Schwartz, jika Anda peduli dengan urutannya, Anda harus membuat kode secara eksplisit beberapa poin urutan

Pada akhirnya, jika kode Anda bergantung pada beberapa urutan, kode tersebut sama sekali tidak dapat dibaca dan karena alasan keterbacaan yang sederhana, Anda sebaiknya menghindari pengkodean dengan cara ini.

person Basile Starynkevitch    schedule 29.10.2014
comment
Jika Anda peduli, Anda perlu memasukkan titik urutan di antara pemanggilan fungsi. Seperti result=function_1(); result*=function_2();. - person David Schwartz; 29.10.2014
comment
Ini tidak dapat menyebabkan perilaku tidak terdefinisi (kecuali function_1 atau function_2 adalah makro). Ada titik urutan sebelum dan sesudah badan fungsi. - person M.M; 29.10.2014
comment
Jika function_1 dan function_2 dimasukkan, saya yakin kompiler mungkin mengoptimalkan untuk mencampur kedua kode... - person Basile Starynkevitch; 29.10.2014
comment
Tetap tidak bisa menyebabkan UB, compiler harus mematuhi aturan as-if - person M.M; 29.10.2014
comment
Terima kasih tentang UB. Tingkatkan jawaban saya! - person Basile Starynkevitch; 29.10.2014
comment
Ini tidak ditentukan terlalu kabur. Sepertinya standar C++ tidak menjelaskan apa pun tentang ini. Tapi itu benar. Ini menentukan bahwa urutan evaluasi tidak ditentukan. Jadi pernyataan yang lebih tepat adalah urutan evaluasi subekspresi tidak ditentukan. - person Kerrek SB; 29.10.2014
comment
Saya pikir perkalian menghasilkan hasil yang sama dalam kedua kasus (kiri dievaluasi terlebih dahulu, atau kanan dievaluasi terlebih dahulu). Kekhawatiran ini dapat diperiksa dengan menempatkan break point di setiap fungsi dan test, compiler yang digunakan akan mengikuti urutan apa. - person Ali Kazmi; 29.10.2014
comment
Tidak dengan static int i; int function_1(void) {i+=1; return i;}; int function_2(void) {i+=2; return i;} - person Basile Starynkevitch; 29.10.2014

Menurut Standar C++ (Eksekusi Program 1.9)

15 Kecuali jika disebutkan, evaluasi operan dari masing-masing operator dan subekspresi dari ekspresi individual tidak dilakukan berurutan.

Jadi dalam ungkapan ini

result= function_1()*function_2();

beberapa kompiler dapat mengevaluasi terlebih dahulu function_1() dan kemudian function_2() sementara kompiler lain dapat mengevaluasi terlebih dahulu function_2() dan baru kemudian function_1(). Bahkan jika Anda menulis seperti itu

result= (function_1())*(function_2());

or

result= (function_1())*function_2();

or

result= function_1()*(function_2());

tidak ada yang akan berubah relatif terhadap urutan evaluasi operan.

person Vlad from Moscow    schedule 29.10.2014