rahnema1
پنج شنبه 15 خرداد 1393, 23:59 عصر
می دونیم که در زبانهایی مثل c یا ++cو هم خانواده های اون مثل java و #C از عملگرهای انتساب مرکب یا Compound assignment مثل =+ یا =* استفاده میشه که می خواهم عملکرد اینها را بررسی کنم
از ویژگی این زبانها قابلیت زنجیروار نوشتن اینجور عبارات هست
نتیجه برنامه زیر در هر سه زبان چی میشه ؟ و چرا؟
int a=1;
a+=a+=4;
در جاوا و سی شارپ به جواب 6 می رسیم و در سی و سی پلاس پلاس به جواب 10 می رسیم
با گشت و گذاری در استاندارد زبانهای مذکور به این نکات بر می خوریم:
تقدم عملگرها که یکسانه و در تمام زبانهای مذکور عملگر انتساب از راست به چپ گروه میشه یعنی اگه بخواهیم داخل پرانتز بذاریم این جور میشه
a+=(a+=4);
یک نکته در زبانهای جاوا و سی شارپ وجود داره که فارغ از تقدم و شرکت پذیری عملگر ها، در این زبانها تضمین شده که عبارتها از چپ به راست اجرا بشن
یعنی در عبارتی مثل a+b در سی شارپ و جاوا ابتدا a و سپس b برآورد میشن و بعد عمل جمع انجام میشه
نکته دیگه اینه که در زبانی مثل جاوا در خصوص عملگر مرکب مثل =+ وقتی که عملوند سمت چپ قراره در ابتدا برآورد بشه مقدار اون استخراج و در جایی ذخیره می شه
بعد عملوند سمت راست برآورد میشه و مقدار اون با مقدار ذخیره شده جمع میشه و در عملوند سمت چپ ذخیره میشه
حالا عبارت مورد نظر را بررسی می کنیم:
ابتدا ما a که در سمت چپ قرار داره برآورد می کنیم که مقدار 1 داره این مقدار در جایی نگه می داریم بعد به عملوند سمت راست می رسیم یعنی عبارتی که داخل پرانتز قرار داره
باز داخل پارنتز با a مواجه می شیم که مقدار اون 1 هست در جایی نگه می داریم بعد به عملوند سمت راست می رسیم که 4 هست و اون را با مقداری که نگه داشتیم یعنی 1 جمع می کنیم و در a می گذاریم
پس جواب پرانتز برابر میشه با 5 حالا ما مقدار a را که در ابتدا ذخیره کرده بودیم یعنی 1 را با 5 جمع می کنیم که جواب برابر 6 می شه
اما در سی پلاس پلاس در خصوص بیشتر عملگرها ( به جز عملگرهایی که استثنا شده اند ) معلوم نیست کدام عملوند یک عملگر زودتر اجرا میشه. مثلا در عبارت a+b معلوم نیست ابتدا a برآورد میشه یا b
در مورد عملگری مثل =+ ما دو تا برآورد و یک اثر جانبی داریم یعنی عملوندهای سمت راست و چپ ابتدا برآورد میشن بدون اینکه ترتیب برآورد اونها معلوم باشه سپس یک اثر جانبی اتفاق می افته که عبارت است از تغییر مقدار عملوند سمت چپ
نکته دیگه اینکه در مورد این عملگر در سی پلاس پلاس تضمین شده که تغییر مقدار عملوند سمت چپ بعد از دو برآورد مذکور انجام میشه
حالا یک قانون در سی پلاس پلاس داریم که اگه روی یک متغیر عددی اثر جانبی اعمال بشه و در همان زمان روی اون متغیر یک اثر جانبی دیگه اعمال بشه یا در همان زمان مقدار برآورد شده اون متغیر استفاده بشه و در عین حال ترتیب انجام کامل اونها معین نباشه در نتیجه حالتی به وجود میاد به نام رفتار تعریف نشده یا undefined behavior
یعنی از نظر استاندارد سی پلاس پلاس تعریف نشده
حالا در تحلیل عبارت بالا می بینیم که a سمت چپ شامل یک برآورد و یک اثر جانبی هست و سمت راست =+ که پرانتز قرار داره داخل پرانتز داره روی a اثر جانبی اعمال میشه ( یعنی مقدار a تغییر می کنه)
بنابراین مواجه با حالتی می شیم که یک برآورد( در سمت چپ) و یک اثر جانبی ( درسمت راست و داخل پرانتز) داره روی a انجام میشه بدون اینکه ترتیب اونها معلوم باشه که با رفتار تعریف نشده مواجه می شیم. حالا هر نتیجه ای که این عبارت داشته باشه اهمیت نداره مهم اینه که طبق استاندارد این رفتار تعریف نشده هست
اگرچه در مورد داده های اتمیک در استاندارد سی نشان داده شده که در مورد عبارتی مثل a+=b مراحل به این ترتیبه:
ابتدا آدرس a اخذ میشه بعد مقدار b برآورد میشه و با مقدار موجود در اون آدرس جمع شده و داخل a ریخته میشه.
اما در موردی که این عمل روی یک متغیر بصورت زنجیروار انجام بشه طبق استاندارد تعریف نشده هست
با این حساب عبارتی مثل a=a=4 هم چنین حالتی داره
من فکر می کنم عملکرد انتساب مرکب زنجیروار در سی پلاس پلاس نسبت به جاوا جذابیت بیشتری داره اما در عمل مشخص شد که این کار موجب رفتار تعریف نشده میشه
در مورد جاوا هم به غیر از عملگر اولی ، بقیه عملگرهایی که به دنبال اولی میان عملا بی استفاده می مونن. مثلا عبارت a+=a+=4 عملا تبدیل میشه به a+=a+4
پس زنجیروار نوشتن عملگر انتساب ایده خوبی به نظر نمی رسه مگه اینکه در این زنجیر متغیرهای مختلفی استفاده بشن مثل a+=b+=c
دوستان اگه نظری دارین یا اشکالی می بینید دریغ نفرمایید
از ویژگی این زبانها قابلیت زنجیروار نوشتن اینجور عبارات هست
نتیجه برنامه زیر در هر سه زبان چی میشه ؟ و چرا؟
int a=1;
a+=a+=4;
در جاوا و سی شارپ به جواب 6 می رسیم و در سی و سی پلاس پلاس به جواب 10 می رسیم
با گشت و گذاری در استاندارد زبانهای مذکور به این نکات بر می خوریم:
تقدم عملگرها که یکسانه و در تمام زبانهای مذکور عملگر انتساب از راست به چپ گروه میشه یعنی اگه بخواهیم داخل پرانتز بذاریم این جور میشه
a+=(a+=4);
یک نکته در زبانهای جاوا و سی شارپ وجود داره که فارغ از تقدم و شرکت پذیری عملگر ها، در این زبانها تضمین شده که عبارتها از چپ به راست اجرا بشن
یعنی در عبارتی مثل a+b در سی شارپ و جاوا ابتدا a و سپس b برآورد میشن و بعد عمل جمع انجام میشه
نکته دیگه اینه که در زبانی مثل جاوا در خصوص عملگر مرکب مثل =+ وقتی که عملوند سمت چپ قراره در ابتدا برآورد بشه مقدار اون استخراج و در جایی ذخیره می شه
بعد عملوند سمت راست برآورد میشه و مقدار اون با مقدار ذخیره شده جمع میشه و در عملوند سمت چپ ذخیره میشه
حالا عبارت مورد نظر را بررسی می کنیم:
ابتدا ما a که در سمت چپ قرار داره برآورد می کنیم که مقدار 1 داره این مقدار در جایی نگه می داریم بعد به عملوند سمت راست می رسیم یعنی عبارتی که داخل پرانتز قرار داره
باز داخل پارنتز با a مواجه می شیم که مقدار اون 1 هست در جایی نگه می داریم بعد به عملوند سمت راست می رسیم که 4 هست و اون را با مقداری که نگه داشتیم یعنی 1 جمع می کنیم و در a می گذاریم
پس جواب پرانتز برابر میشه با 5 حالا ما مقدار a را که در ابتدا ذخیره کرده بودیم یعنی 1 را با 5 جمع می کنیم که جواب برابر 6 می شه
اما در سی پلاس پلاس در خصوص بیشتر عملگرها ( به جز عملگرهایی که استثنا شده اند ) معلوم نیست کدام عملوند یک عملگر زودتر اجرا میشه. مثلا در عبارت a+b معلوم نیست ابتدا a برآورد میشه یا b
در مورد عملگری مثل =+ ما دو تا برآورد و یک اثر جانبی داریم یعنی عملوندهای سمت راست و چپ ابتدا برآورد میشن بدون اینکه ترتیب برآورد اونها معلوم باشه سپس یک اثر جانبی اتفاق می افته که عبارت است از تغییر مقدار عملوند سمت چپ
نکته دیگه اینکه در مورد این عملگر در سی پلاس پلاس تضمین شده که تغییر مقدار عملوند سمت چپ بعد از دو برآورد مذکور انجام میشه
حالا یک قانون در سی پلاس پلاس داریم که اگه روی یک متغیر عددی اثر جانبی اعمال بشه و در همان زمان روی اون متغیر یک اثر جانبی دیگه اعمال بشه یا در همان زمان مقدار برآورد شده اون متغیر استفاده بشه و در عین حال ترتیب انجام کامل اونها معین نباشه در نتیجه حالتی به وجود میاد به نام رفتار تعریف نشده یا undefined behavior
یعنی از نظر استاندارد سی پلاس پلاس تعریف نشده
حالا در تحلیل عبارت بالا می بینیم که a سمت چپ شامل یک برآورد و یک اثر جانبی هست و سمت راست =+ که پرانتز قرار داره داخل پرانتز داره روی a اثر جانبی اعمال میشه ( یعنی مقدار a تغییر می کنه)
بنابراین مواجه با حالتی می شیم که یک برآورد( در سمت چپ) و یک اثر جانبی ( درسمت راست و داخل پرانتز) داره روی a انجام میشه بدون اینکه ترتیب اونها معلوم باشه که با رفتار تعریف نشده مواجه می شیم. حالا هر نتیجه ای که این عبارت داشته باشه اهمیت نداره مهم اینه که طبق استاندارد این رفتار تعریف نشده هست
اگرچه در مورد داده های اتمیک در استاندارد سی نشان داده شده که در مورد عبارتی مثل a+=b مراحل به این ترتیبه:
ابتدا آدرس a اخذ میشه بعد مقدار b برآورد میشه و با مقدار موجود در اون آدرس جمع شده و داخل a ریخته میشه.
اما در موردی که این عمل روی یک متغیر بصورت زنجیروار انجام بشه طبق استاندارد تعریف نشده هست
با این حساب عبارتی مثل a=a=4 هم چنین حالتی داره
من فکر می کنم عملکرد انتساب مرکب زنجیروار در سی پلاس پلاس نسبت به جاوا جذابیت بیشتری داره اما در عمل مشخص شد که این کار موجب رفتار تعریف نشده میشه
در مورد جاوا هم به غیر از عملگر اولی ، بقیه عملگرهایی که به دنبال اولی میان عملا بی استفاده می مونن. مثلا عبارت a+=a+=4 عملا تبدیل میشه به a+=a+4
پس زنجیروار نوشتن عملگر انتساب ایده خوبی به نظر نمی رسه مگه اینکه در این زنجیر متغیرهای مختلفی استفاده بشن مثل a+=b+=c
دوستان اگه نظری دارین یا اشکالی می بینید دریغ نفرمایید