PDA

View Full Version : مقاله: انتساب مرکب زنجیروار در سی پلاس پلاس ، جاوا و سی شارپ



rahnema1
پنج شنبه 15 خرداد 1393, 22: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

دوستان اگه نظری دارین یا اشکالی می بینید دریغ نفرمایید

motherboard
پنج شنبه 15 خرداد 1393, 23:59 عصر
پس زنجیروار نوشتن عملگر انتساب ایده خوبی به نظر نمی رسه مگه اینکه در این زنجیر متغیرهای مختلفی استفاده بشن مثل a+=b+=c

ولی به نظر من ایده خوبی هستش.عوض اینکه چند تا متغیر تعریف کنیم.از یک متغیر استفاده می کنیم.و این خودش حافظه کم تری رو مصرف می کنه.

#include <conio.h>
#include <stdio.h>
using namespace std;
int main()
{
int a=1;
a+=a+=4;
printf("%d",a);
getch();}

omid_kma
جمعه 16 خرداد 1393, 02:15 صبح
یک نکته کوچیک اگر توی gcc وارنینگ Wsequence point - رو فعال کنید زمان هایی که دارید استفاده غیر مجاز می کنید وارنینگ undefined behavior میده .
البته یکم سخت گیری هم می کنه مثلا i=++i از C++‎‎11 به بعد دیگه undefine نیست ولی gcc وارنینگ میده (البته ۴.۹ رو هنوز تست نکردم ۴.۸ که این طوره )
این قواعد مخصوصا چیزایی که از C++‎‎11 اضافه شدن درکشون تا حدی پیچیدست ولی خب می تونید با یک کار ساده از این جور مشکلات جلوگیری کتید
هیچ وقت قبل از ; دو بار از یک متغیر استفاده نکنین . (البته به غیر از چیزایی مثل i = i+2 ,...
ضمنا من مطمین نیستم
a=a=4 جزو undefined behvavior ها حساب بشه چون به هر شکلی هم عبارت محاسبه بشه باز هم نتیجه یکیه

rahnema1
جمعه 16 خرداد 1393, 12:12 عصر
ولی به نظر من ایده خوبی هستش.عوض اینکه چند تا متغیر تعریف کنیم.از یک متغیر استفاده می کنیم.و این خودش حافظه کم تری رو مصرف می کنه.

#include <conio.h>
#include <stdio.h>
using namespace std;
int main()
{
int a=1;
a+=a+=4;
printf("%d",a);
getch();}



درسته که حافظه کمی مصرف می کنه اما اینجو نوشتن یک متغیر پشت سر هم و به صورت زنجیروار اشتباهه و همون undefined behavior هستش. به جاش میشه این جور نوشت:

a+=4;
a+=a;
یا
a+=4,a+=a;

اما اگه در زنجیر، متغیرهای متفاوتی بذاریم دیگه اشتباه مذکور پیش نمیاد

rahnema1
جمعه 16 خرداد 1393, 12:17 عصر
یک نکته کوچیک اگر توی gcc وارنینگ Wsequence point - رو فعال کنید زمان هایی که دارید استفاده غیر مجاز می کنید وارنینگ undefined behavior میده .
البته یکم سخت گیری هم می کنه مثلا i=++i از C++‎‎11 به بعد دیگه undefine نیست ولی gcc وارنینگ میده (البته ۴.۹ رو هنوز تست نکردم ۴.۸ که این طوره )
این قواعد مخصوصا چیزایی که از C++‎‎11 اضافه شدن درکشون تا حدی پیچیدست ولی خب می تونید با یک کار ساده از این جور مشکلات جلوگیری کتید
هیچ وقت قبل از ; دو بار از یک متغیر استفاده نکنین . (البته به غیر از چیزایی مثل i = i+2 ,...
ضمنا من مطمین نیستم
a=a=4 جزو undefined behvavior ها حساب بشه چون به هر شکلی هم عبارت محاسبه بشه باز هم نتیجه یکیه

در مورد a=a=4 نظر شما درسته و undefined behavior پیش نمیاد. اون جمله استاندارد را درست مطالعه نکرده بودم
If a side effect on a scalar object is unsequenced relative to either anotherside effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

مخصوصا وقتی میگه using the value of چون اینجا مقدار a در سمت چپ برآورد نمیشه بلکه آدرسش برآورد میشه
اما انتساب مرکب مقدار برآورد میشه