Foo (bar ()) kabi kodda funktsiyani bajarish tartibi nimadan iborat?

C yoki C ++ da shunga o'xshash kod mavjud:

foo(bar());

Bu holatda vazifani bajarish tartibi nimada?

  1. Birinchi bar() deb nomlanadi va foo() kodini bar() foo() = bar() ning qaytib keladigan qiymatini bildiradi.
  2. Derleyici yuqoridagi tartibni o'zgartiradi, ya'ni foo() deb ataladi va bar() kodini foo() parametrining qiymati qanaqa zarur?

2-vaziyatda foo() quyidagi kabi aniqlanishi kerak bo'lsa, optimallash uchun foydali bo'lishi mumkin:

void foo(someType par) {
    if(someTest())
        baz1();
    else
        baz2(par);
}

someTest() FALSE so'zini qaytarsa, bu holda bar() chaqiruvi butunlay o'tkazib yuborilishi mumkin.

Shu bilan birga, 2-holat, shuningdek dasturchini ham ehtiyot bo'lishga majbur qiladi, chunki u ba'zida nozik xatoga olib kelishi mumkin (masalan, takroran).

1
bar() birinchi deb nomlanadi.
qo'shib qo'ydi muallif Jesper Juhl, manba
Uzoq vaqt davomida kuzatiladigan harakatlar bir xil bo'lsa, hech qanday funktsiya chaqiruvi bo'lmasligi mumkin. Va bir tilini tanlang! C va C ++ tillari turli xil semantikaga ega!
qo'shib qo'ydi muallif Olaf, manba
qo'shib qo'ydi muallif Johan Lundberg, manba

6 javoblar

C ++ da, [intro.execution]:

Funktsiyani chaqirganda (funktsiya inline bo'ladimi-yo'qmi), har qanday qiymatni hisoblash va har qanday dalil ifodasi bilan bog'liq yon ta'sir yoki chaqirilgan funksiyani bildiruvchi postfiks ifodasi bilan har qanday ifoda yoki ifodani bajarishdan oldin tartiblanadi. deb nomlanadi

bar() must be evaluated before the call to foo begins.

a (b) ifodasi endi a kodini b oldidan baholagan bo'lsa, ular C ++ 17 da o'zgarish sodir bo'lmadi. Bunday holda foo ning baholashi hech narsa qilmaydi, bu faqat identifikator. Lekin foo() (bar ()) bo'lsa, foo() ga qo'ng'iroq qilish bar() , shuning uchun C ++ 17 dan oldin ikkala ikkita narsa aniqlanmadi.

5
qo'shib qo'ydi
Yo'q, yo'q, faqat kuzatiladigan xatti-harakatlarini tushuntirib beradi. Kuzatiladigan xatti-harakat bar() birinchi marta baholanadi.
qo'shib qo'ydi muallif Barry, manba
@Olaf: a "chaqirilgan funksiyani belgilaydigan postfiks ifodasi"
qo'shib qo'ydi muallif rici, manba
@Olaf: Lekin 1.9 [intro.execution] "[bajarishga mos keluvchi] mavhum mashinaning tuzilishini nusxa ko'chirish yoki taqlid qilish kerak emas, aksincha, tatbiqga mos keluvchi mavhum mashinaning quyida aytib o'tilganidek kuzatiladigan harakatlarini taqlid qilish kerak. " Bundan tashqari, "oldin tartiblangan" uchun ham amal qiladi; tartibda bajarilishi uchun faqat kuzatiladigan harakatlar talab etiladi.
qo'shib qo'ydi muallif rici, manba
@Olaf: Men sizning Aniqligingizdan xabardorman :) va aslida u C ++ standartidan (men 1.9.1 yozdim). Ammo bu aslida C standartidagi "ilgari ketma-ketlik" bilan bir xil ta'rif (garchi tartibda - oldin qoidalar farqli bo'lsa); har ikkala holatda ham u faqat kuzatilgan xatti-harakatlar uchun qo'llaniladi. (C ++ va C har xil xatti-harakatlarni kuzatishi mumkin, lekin bular men bilan juda o'xshash.)
qo'shib qo'ydi muallif rici, manba
"... postfiks ifoda etuvchi ..." - nima bo'lsa ham, men aniq muddatni eslamadim. Bu nuqta, javobning javob funktsiyasi emas, aniqdir.
qo'shib qo'ydi muallif Olaf, manba
Men sizning sharhingizdan olganman, ammo javobimga javob berilmaydi, bu mening fikrimga to'g'ri keladi. Emas, balki C ++ 17 (hech bo'lmaganda) kamroq baholashni qo'llab-quvvatlamaydimi? Bu savolni juda keng darajaga olib chiqadi, deb o'ylayman.
qo'shib qo'ydi muallif Olaf, manba
Taqqoslash kodi a va b bir-biriga nisbatan baholanishi bilan bog'liq emas. a funktsiyasi emas, balki funktsiyaga ega ifoda. Tananing funktsiya ta'rifidagi kodi.
qo'shib qo'ydi muallif Olaf, manba
@rici: Agar siz C ++ standartiga murojaat qilsangiz: Men bunga qo'shilmayman (men C menman). Agar shunday bo'lsa, u javoblarning bir qismi bo'lishi kerak, chunki u haqiqatan ham talablarni tinchlantiradi. Men faqat ko'rsatilgan matndan ishora qilishni istadim, bu C ga qaraganda qattiqroq bo'ladi.
qo'shib qo'ydi muallif Olaf, manba
"deb ataladi. Har bir ifoda yoki ifodani bajarishdan oldin chaqirgan funktsiyaning tanasida joylashgan». - bu kuzatiladigan xatti-harakatlardan ancha uzoqlashadi. OB so'zlarni o'zboshimchalik bilan qayta tartibga solish imkonini beradi, chunki OB o'zgarmaydi. Bu chiziq uni man qilishni taqiqlaydi. Buning sababi C ++ ning tuzuvchilari/destructorlari va boshqalar bo'lishi mumkin. Ammo, bu C ga nisbatan aniqroq yo'l bilan cheklanadi (bu savolga afsuski, ikkalasiga ham yozilgan).
qo'shib qo'ydi muallif Olaf, manba
Bu shovqinni va to'liq kodni optimallashtirishga to'sqinlik qiladi. Agar bu C ++ haqida bo'lsa, u C uchun juda farq qiladi.
qo'shib qo'ydi muallif Olaf, manba
      
  1. bar() nomi bilan birinchi [...] deb nomlanishi kerakmi?
  2.   

Kod o'zida nima sodir bo'layotganidek harakat qilish talab etiladi.

      
  1. Derleyici, yuqoridagi [...] qayta tartibga solinishi mumkinmi?
  2.   

Ha, agar kuzatiladigan xatti-xarakat bir xil bo'lsa, bar() birinchi baholandi.

Bunga "rozi" qoida deb nom berilgan.

[...] agar ushbu dastur xalqaro standartning talablariga rioya qilmasa, natija dasturning kuzatilishi mumkin bo'lgan xatti-harakatlaridan kelib chiqadigan talabga muvofiq bo'lgan taqdirda amalga oshiriladi.

3
qo'shib qo'ydi
@NathanOliver Ha, bu bilan bog'liq Q & A standart quotes bu qo'llab-quvvatlash ko'rinadi.
qo'shib qo'ydi muallif emlai, manba
Ishonchingiz komilmi? [expr.call] vaziyatlar Postfiks ifodasi va argumentlarni baholash bir-biriga nisbatan unchalik muhim emas. Argumentlar bahosining barcha yon ta'siri funktsiya kiritilmasdan oldin tartiblangan
qo'shib qo'ydi muallif NathanOliver, manba

Boshqalarning aytgan so'zlaridan tashqari, siz ham e'tiborga olishingiz mumkin

  foo( bar1(), bar2() );

bu yanada qiziqarli ish. Bu erda buyurtma [bar1, bar2, foo] yoki [bar2, bar1, foo] bo'lishi mumkin.

2
qo'shib qo'ydi

Agar sizda quyidagi so'zlar bo'lsa

foo(bar());

bar() funksiyasi foo() dan oldin chaqiriladi. Derleyici bu funktsiya chaqiruvlarini qayta tartiblay olmaydi.

0
qo'shib qo'ydi

Funktsional dalillar baholashdan so'ng (ya'ni, biron bir funktsiya kodi kiritilguncha) ketma-ketlik nuqtasi mavjud. Shuning uchun foo (...) kiritilmasdan oldin bar() qiymatini baholash kerak. Misol uchun, C11 standartidagi :

6.5.2.2 Funktsiya chaqiruvi: (10) Funktsional identifikator va haqiqiy dalillarni baholashdan keyin, lekin haqiqiy chaqiruvdan oldin ketma-ketlik nuqtasi mavjud. Boshqa funktsiyalarni chaqiruvchi funktsiyadagi (masalan, boshqa funktsiya chaqiruvlari) har qanday baholash, chaqirilgan funksiya tanasining bajarilishidan oldin yoki keyin maxsus tartibda bo'lmagan har qanday baholash, bu funktsiyani amalga oshirilishi bilan aniq belgilanadi.

0
qo'shib qo'ydi
Malumot uchun eski versiyani emas, balki joriy standartidan foydalaning. Va bu ishlab chiqarilgan mashina kodi qanday ishlashini ko'rsatmaydi.
qo'shib qo'ydi muallif Olaf, manba

Xuddi shunday:

type bar_result = bar();
foo(bar_result);
  1. bar() birinchi bo'lib chaqiriladi.
  2. bar_result nusxa/havola sifatida qabul qilinadi.
0
qo'shib qo'ydi
void foo (const turi &) {}
qo'shib qo'ydi muallif emlai, manba
bar() natijasi, masalan, foo o'z parametrini mos yozuvlar sifatida qabul qilsa, masalan, nusxa ko'chirish sifatida kiritilmasligi kerak.
qo'shib qo'ydi muallif emlai, manba
Sizga misol keltirasizmi?
qo'shib qo'ydi muallif J.Guarin, manba
Siz haqsiz. Javobni yaxshilashni xohlayman. Rahmat.
qo'shib qo'ydi muallif J.Guarin, manba