PDA

View Full Version : مبتدی: سوال در مورد عملگر افزایشی (++)



mobtadi1
سه شنبه 18 خرداد 1395, 23:56 عصر
سلام.
چرا نتیجه دستور زیر ۳.۰۰ میشه، در حالیکه انتظار دارم ۲.۰۰ بشه!
وقتی هم عملگر افزایشی قبل از x قرار می‌گیره، نتیجه ۴ میشه. چرا؟ آیا نباید جواب باز هم ۲ باشه؟ در سطر که عبارت رو نوشتم، هیچ محاسبه‌ای انجام ندادم، و فقط مجموع ایکس رو چاپ کردم؛ چرا نتیجه ۴ شد؟

int main(){
float x;
x=1.00;
x+=x++;
printf("%.2f",x);
return 0;
}

hsn_secret
چهارشنبه 19 خرداد 1395, 01:50 صبح
برنامه درست هستش و دقیقا باید جواب 3 رو برای شما نشون بده .
اگه دارید از خودتون می پرسید که چرا 2 نشد ، به این دلیل هستش که روند اجرای عملگر افزایشی رو به طور اشتباه متوجه شدید .
هنگامی که از ++x استفاده می کنید ، در واقع مقدار فعلی x به خروجی میره و در آخر یک واحد به مقدار اون اضافه میشه
و اما در x++ ، در واقع در ابتدا یک واحد به مقدار x افزوده میشه و در آخر به خروجی میره .
تفاوت این دو رو در هنگام چاپ کردن میتونید متوجه بشید .

در بالا هم ابتدا مقدار x یک هستش و در سطر بعد
ابتدا ++x یک واحد به مقدار فعلی x اضافه میشه ، که در واقع میشه 2 و بعد عملگر + پشت x هنگام انتساب یک واحد به اون 2 اضافه میکنه که میشه 3 .

mobtadi1
چهارشنبه 19 خرداد 1395, 17:32 عصر
از توضیحی که دادین متوجه اشتباه شدم. مرسی.
اما موضوع اینه که باید در صورتیکه عملگر افزایشی قبل از متغیر قرار بگیره، نتیجه ۳ بشه، اینطور نیست؟ یعنی سوال من مانند سوال زیر هست، سوال زیر هم جواب باز هم ۳ میشه، در حالیکه فقط x با x باید جمع بشه و عملگر افزایشی چون بعد از متغیر اومده نباید مقداری رو اضافه کنه: جواب زیر باید ۲ باشه:
float x;
x=1.00;
x=x+x++;
printf("%.2f",x);
return 0;

و برام جالبه با این همه مثالی که خوندم، باز هم این مشکلی که برای خودم پیش میاد رو درک نمیکنم! جواب کد زیر باید ۳ باشه، اما ۴ میشه!

float x;
x=1.00;
x=x+(++x);
printf("%.2f",x);

من در چند وبسایت خوندم که «اگر عملگر افزایشی بعد از متغیر قرار بگیره، افزایش در عبارت جاری اعمال نمیشه». برای مثال (http://www.c4learn.com/c-programming/c-increment-operator/): a بعد از چاپ برابر با ۱۱ نمیشه، که خوب، کد زیر درسته.
int a,b,x=10,y=10;
a = x++;
b = ++y;
printf("Value of a : %d",a);
printf("Value of b : %d",b);

ASM6502
چهارشنبه 19 خرداد 1395, 22:04 عصر
و برام جالبه با این همه مثالی که خوندم، باز هم این مشکلی که برای خودم پیش میاد رو درک نمیکنم! جواب کد زیر باید ۳ باشه، اما ۴ میشه!

float x;
x=1.00;
x=x+(++x);
printf("%.2f",x);



برنامه بالا در واقع به این صورت اجرا میشه :
x=1.00;
++x;
x=x+x;

x=1
x=2
x=2+2=4

پس نتیجه 4 صحیح هست.

mobtadi1
چهارشنبه 19 خرداد 1395, 23:34 عصر
برنامه بالا در واقع به این صورت اجرا میشه :
...
پس نتیجه 4 صحیح هست.

ممنون. اما اگر قرار باشه به اینصورت خودم رو توجیه کنم، پس از گذراندن دوره سی، فقط جواب سوالات خودم رو می‌تونم بدم :لبخندساده:
برای من این پاسخ قانع کننده نیست؛ اگرچه شاید پاسخ شما درست باشه.

امیدوارم اگر کاربری توضیح دیگه‌ای داره ارسال کنه.
مرسی.

amirtork
پنج شنبه 20 خرداد 1395, 00:32 صبح
سلام،
برای درک بهتر ابهاماتی اینچنینی، پیشنهاد میکنم از قابلیت trace که در اکثریت قابل توجهی از کامپایلر ها و دیباگر ها تعبیه شده استفاده کنید.
اگر نیاز به توضیحات بیشتر داشتید، بفرمایید تا من یا دوستان دیگه راهنمایی بیشتری کنیم.

mobtadi1
پنج شنبه 20 خرداد 1395, 02:13 صبح
@amirtork
با استفاده کدبلاکس دیباگ کردم، که جزئیات رو نشون نداد، یعنی x رو ابتدا ۱، و بعد هم ۴ نشون داد. نمی‌دونم تریس کردن چقدر با دیباگ کردن تفاوت داره، اما وقتی تریس رو جستجو کردم، راه و روش‌های دستی رو راهنمایی می‌کردند که برام پیچیده است.

من در مورد عملگرهای افزایشی تمرین کردم، مشکلی نبود، دقیقا همانطور که در توضیحات وب‌سایت‌ها گفته شده کار می‌کنه، اما برام سوال شده که چرا عملگر post-increment -در سوال من- در عبارت جاری عمل میکنه، در حالیکه نباید در عبارت جاری عمل کنه. چرا؟
و چرا عملگر pre-increment که باید مقدار ۳ رو چاپ کنه، مقدار ۴ رو چاپ میکنه؟

ببینید، در کد زیر فقط جای x با مقدار ۱ عوض شده، و نتیجه ۳ شده! که درسته. اما چرا وقتی x که مقدارش برابر با ۱ هست رو قرار میدم نتیجه میشه ۴؟ :لبخند:
float x;
x=1.00;
x=1+(++x);
printf("%.2f",x);
return 0;

لطفا اگر من متوجه نمیشم، ساده بگید «شما متوجه نمیشی».

ASM6502
پنج شنبه 20 خرداد 1395, 11:33 صبح
توی پست قبلیم اون خط رو دقیقا واست تریس کردم
دیگه واضح تر از اون فکر نمیکنم کسی بتونه توضیح بده

یه بار دیگه به زبان فارسی توضیح میدم شاید متوجه شدی :
ایکس مقدارش یک هست
اولویت با محاسبه داخل پارانتز هست.
داخل پارانتز مقدار ایکس یک واحد افزایش پیدا میکنه و ایکس میشه دو. پس داخل پارانتز هم میشه دو
ایکس دیگه مقدارش یک نیست و شده دو و با دوی حاصل از پارانتز جمع میشه میشه چهار

دیباگر و تریس کردن واسه آنالیز کردن این جور عبارات ترکیبی تک خطی جواب نمیده یا حداقل من که بلد نیستم
من خودم اصلا از این جور عبارات ترکیبی خوشم نمیاد چون باعث میشه خوانایی برنامه پایین بیاد
تعجب میکنم که چرا هنوز هم کتاب های برنامه نویسی از این جور مثال ها استفاده میکنن در صورتی که این جور عبارات فقط باعث سردرگمی خواننده میشه و هیچ استفاده ای ندارن.
البته ظاهرا قدیما برنامه نویس های خیلی حرفه ای از این جور عبارات ترکیبی گنگ استفاده میکردن تا کسی نتونه برنامشون رو به راحتی مهندسی معکوس بکنه.

mobtadi1
پنج شنبه 20 خرداد 1395, 13:29 عصر
می‌خواستم بنویسم:
«این مشکل، از نظر من، به دلیل اشتباه کامپایلر هست؛ و اینکه، کامپایلرها هنوز اینقدر دقیق و درست نیستند. چیزی که آموختم اینه که، باید تا حد امکان کد رو ساده نوشت، و روی منطق برنامه تمرکز کرد، و به دنبال پاسخ صحیح بود، و پس از اطمینان به پاسخ برنامه، کد رو بهینه کرد. بهینه کردن کد هم نیاز به درک بالا و تجربه داره.»

اما ترجیح دادم یک بار دیگه در مورد این عملگر مطالعه کنم. در ویکی‌پدیا اومده:

Since the increment/decrement operator modifies its operand, use of such an operand more than once within the same expression can produce undefined results. For example, in expressions such as x − ++x, it is not clear in what sequence the subtraction and increment operations should be performed. Such expressions generally invoke undefined behavior, and should be avoided.


:لبخندساده:

amirtork
پنج شنبه 20 خرداد 1395, 14:17 عصر
سلام مجدد،
در مورد رفتار های نامشخصی که به دلیل استفاده از این عملگر ها اتفاق می افته، جناب rahnama1 توضیحات کاملی رو دادن که از کتاب استاندارد c++ استخراج کرده بودن، پیشنهاد میکنم، اگر به دنبال درک دقیق تر این موضوع و موضوعات اینجنینی هستید، این کتاب رو مطالعه کنید.
این رفتار نامشخص به این دلیل رخ میده که زبان c++ هیچ تضمینی در رابطه با ترتیب اجرای عملگر هایی با اولویت یکسان نمیده، و به همین خاطر توصیه میشه از استفاده از این ترکیب ها مثل swap در یک خط و ... خودداری بشه، اما، همونطور که جناب ASM6502 توضیح دادن، چون شما از پرانتز استفاده کردید، و پرانتز اولویت بالاتری نسبت به عملگر ها ++ و + داره، ابتدا مقدار x به دو تغییر کرده(یعنی عملگر ++ اجرا میشه) و بعد عملگر + کار خودش رو انجام میده، که در نتیجه، خروجی برابر با 4 هست.
امیدوارم مشکل رفع شده باشه.

mobtadi1
پنج شنبه 20 خرداد 1395, 17:48 عصر
سلام مجدد،
در مورد رفتار های نامشخصی که به دلیل استفاده از این عملگر ها اتفاق می افته، جناب rahnama1 توضیحات کاملی رو دادن که از کتاب استاندارد C++‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎ استخراج کرده بودن، پیشنهاد میکنم، اگر به دنبال درک دقیق تر این موضوع و موضوعات اینجنینی هستید، این کتاب رو مطالعه کنید.
این رفتار نامشخص به این دلیل رخ میده که زبان C++‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎ هیچ تضمینی در رابطه با ترتیب اجرای عملگر هایی با اولویت یکسان نمیده، و به همین خاطر توصیه میشه از استفاده از این ترکیب ها مثل swap در یک خط و ... خودداری بشه، اما، همونطور که جناب ASM6502 توضیح دادن، چون شما از پرانتز استفاده کردید، و پرانتز اولویت بالاتری نسبت به عملگر ها ++ و + داره، ابتدا مقدار x به دو تغییر کرده(یعنی عملگر ++ اجرا میشه) و بعد عملگر + کار خودش رو انجام میده، که در نتیجه، خروجی برابر با 4 هست.
امیدوارم مشکل رفع شده باشه.

سلام
به نظرم نقل قول‌ی که از ویکی‌پدیا قرار دادم نیاز به توضیح نداره. بطور خلاصه به‌کار بردن یک عملگر دو بار در یک عبارت که به همراه استفاده از عملگر‌های افزایشی یا کاهشی باشه یک «رفتار تعریف نشده» یا «undefined behavior» است، و نباید از این روش ترکیبی استفاده کرد. یعنی چی؟ یعنی اینکه نویسنده زبان یا کامپایلر در مورد این نوع نحو هیچ رفتار و الگوریتم دقیقی رو تعریف و تایین نکردن و پاسخ داده شده فقط یک پاسخ پیشنهادی است؛ و البته عملکرد هر کامپایلر ممکنه متفاوت باشه.


In computer programming, undefined behavior (UB) is the result of executing computer code that does not have a prescribed behavior by the language specification the code adheres to, for the current state of the program (e.g. memory). This happens when the translator of the source code makes certain assumptions, but these assumptions are not satisfied during execution.

اما این سوال من ربطی به اولویت نداشت، به دلیل اینکه بدون پرانتز هم نتیجه ۴ میشه، یا اگر پس افزایش باشه نتیجه ۳ میشه، درحالیکه در هر صورت در پیش‌افزایش نتیجه ۴ نمیشه، حتی اگر x رو داخل پرانتز قرار بدید. @amirtork، با اینکه نقل قول ویکی‌پدیا رو آوردم، باز هم شما در مورد اولویت گفتید، و توضیح ASM6502 رو تایید کردید، در حالیکه x رو یک بار افزایش دادم نه دوبار، نمیدونم چطور پاسخ ۴ رو صحیح می‌دونید. شما کاری که کامپایلر انجام داده رو توضیح میدی، من میگم بر اساس توضیحات نباید عملگر افزایشی اینطور عمل کنه و این پاسخ رو بده.

اگر قرار بود من پاسخ رو صحیح فرض کنم، خوب خودم همین دلیل رو می‌آوردم، سوال پیچیده‌ای که نبود، علاوه بر اینکه من چند تا مثال برای شما آوردم، به نظر اصلا نگاه نکردید. علاوه بر این، وقتی در مراجع رسمی توضیحی به شیوه عملکردی که شما قبولش دارید داده نمیشه، نباید دلیل بی اصول و ریشه بیارید. این یک موضوع کاملا طبیعی است که حتی اگر کسی حرفه‌ای هم باشه، برای بعضی از سوال‌ها -هر قدر هم پایه‌ای- پاسخی نداشته باشه؛ و اصلا ایراد و عیب کسی نیست.

ویکی‌پدیا تائید کرد که این گونه ترکیب دستورات اشتباست و تعریف نشده است و باعث ایجاد خطا میشه.
خلاصه رو نوشتم، گفتم شاید توضیحات رو نخونید :)

amirtork
پنج شنبه 20 خرداد 1395, 22:43 عصر
سلام
به نظرم نقل قول‌ی که از ویکی‌پدیا قرار دادم نیاز به توضیح نداره. بطور خلاصه به‌کار بردن یک عملگر دو بار در یک عبارت که به همراه استفاده از عملگر‌های افزایشی یا کاهشی باشه یک «رفتار تعریف نشده» یا «undefined behavior» است، و نباید از این روش ترکیبی استفاده کرد. یعنی چی؟ یعنی اینکه نویسنده زبان یا کامپایلر در مورد این نوع نحو هیچ رفتار و الگوریتم دقیقی رو تعریف و تایین نکردن و پاسخ داده شده فقط یک پاسخ پیشنهادی است؛ و البته عملکرد هر کامپایلر ممکنه متفاوت باشه.

اما این سوال من ربطی به اولویت نداشت، به دلیل اینکه بدون پرانتز هم نتیجه ۴ میشه، یا اگر پس افزایش باشه نتیجه ۳ میشه، درحالیکه در هر صورت در پیش‌افزایش نتیجه ۴ نمیشه، حتی اگر x رو داخل پرانتز قرار بدید. @amirtork، با اینکه نقل قول ویکی‌پدیا رو آوردم، باز هم شما در مورد اولویت گفتید، و توضیح ASM6502 رو تایید کردید، در حالیکه x رو یک بار افزایش دادم نه دوبار، نمیدونم چطور پاسخ ۴ رو صحیح می‌دونید. شما کاری که کامپایلر انجام داده رو توضیح میدی، من میگم بر اساس توضیحات نباید عملگر افزایشی اینطور عمل کنه و این پاسخ رو بده.

اگر قرار بود من پاسخ رو صحیح فرض کنم، خوب خودم همین دلیل رو می‌آوردم، سوال پیچیده‌ای که نبود، علاوه بر اینکه من چند تا مثال برای شما آوردم، به نظر اصلا نگاه نکردید. علاوه بر این، وقتی در مراجع رسمی توضیحی به شیوه عملکردی که شما قبولش دارید داده نمیشه، نباید دلیل بی اصول و ریشه بیارید. این یک موضوع کاملا طبیعی است که حتی اگر کسی حرفه‌ای هم باشه، برای بعضی از سوال‌ها -هر قدر هم پایه‌ای- پاسخی نداشته باشه؛ و اصلا ایراد و عیب کسی نیست.

ویکی‌پدیا تائید کرد که این گونه ترکیب دستورات اشتباست و تعریف نشده است و باعث ایجاد خطا میشه.
خلاصه رو نوشتم، گفتم شاید توضیحات رو نخونید :)

دوست عزیز، اگر دقت کرده باشید، من هم صرفا کتابی رو برای پیشنهاد دادم که در صورت علاقه مندی مطالعه کنید تا اطلاعات بیشتری در این مواردی از این قبیل کسب کنید و متممی به توضیحاتی که ارائه داید اضافه نکردم! چون نیازی ندیدم.
و در مورد استفاده از عملگر های افزایشی/کاهشی، ضمن استناد به نقل قولی که ارائه کردید و باتوجه به درکی که من تا به حال از نحوه ی اجرای این عملگر ها داشتم، به دلیل اینکه این عملگر ها مقدار متغیر رو تغییر میدن و همچنین عدم تضمین ترتیب اجرای عملگر هایی با اولویت یکسان در زبان c++، امکان پیش بینی خروجی امکان نداره، اما این زبان تضمین کرده که اولویت های عملگر ها طبق جدولی که ارائه شده و با یک جست و جو ساده میتونید به اون دست پیدا کنید، رعایت میشه، در این جدول عملگر () از اولویت بالاتری نسبت به عملگر های ++ و + برخورددار هست، بنابراین ابتدا عبارت داخل پرانتز محاسبه خواهد شد که خواهیم داشت: x = 1+x = 2 ، و سپس، عبارت خارج پرانتز که خواهیم داشت x + 2 = 2 + 2 = 4. اما در مورد اینکه فرمودید در کدی که از () استفاده نشده هم مقدار خروجی برابر 4 هست، در اون نسخه از کد، دچار مشکل رفتار تعریف نشده هستیم، اما در نسخه ای که از پرانتز استفاده شده، خیر.
و در مورد اشکالی که به شخص من وارد کردید، من در حد توان خودم، صورت مسئله و توضیحات همه ی عزیزان رو با دقت مطالعه میکنم، اما با این وجود خطای انسانی در بین همه وجود داره! که البته در این مورد، من علت اینکه شما این موضوع رو مطرح کردید متوجه نشدم.
توضیحاتی که من خدمتتون دارم، مخلوطی از دستورالعمل های موجود در مورد ترتیب عملگر ها و نحوه ی عملکرد عملگر ++ بود؛ و فکر نمیکنم چندان بی پایه و بدون ریشه باشند و در آخر هم، تنها نکته ای رو مطرح میکنم و اون هم این هست که ویکی پدیا، منبعی رسمی و کاملا قابل اطمینان نیست، برای اطلاعات بیشتر به این لینک (https://en.wikipedia.org/wiki/Reliability_of_Wikipedia) مراجعه کنید.
در هر حال، به دلیل جبهه گیری های احتمالی و امکان منحرف شدن تاپیک از موضوع اصلی؛ من از ادامه دادن تاپیک خودداری میکنم، با وجود اینکه فکر میکنم پاسخ سوالتون رو بدست آوردید، امیدوارم در صورتی که ابهام ها همچنان برقرار بود، عزیزانی که توانایی بیشتری در توضیح دادن این موضوع دارند پاسخ بدن.

rahnema1
شنبه 22 خرداد 1395, 12:43 عصر
سلام
ببینید قواعد مربوط به برآورد شدن عبارات در استاندارد زبان ++C اومده که می تونید در این سایت (https://isocpp.org/std/the-standard) فایل pdf مربوط به آخرین پیش نویسهای این استاندارد را دانلود کنید:
در بخش 1.9 یک سری تعریف ها و قواعدی مربوط بین ترتیب براورد عملوند های یک عملگر اومده
اونجا گفته شده که در برآورد شدن (evaluation) هر عبارت ممکنه یا الف) محاسبه مقدار (value computation) صورت بگیره (که می تونه شامل مشخص کردن آدرس یا شناسه (identity) جایی که قراره چیزی در اون قرار بگیره باشه یا بیرون کشیدن مقداری (value) که ذخیره شده باشه) یا ب) اثرات جانبی (side effect) ضورت بگیره. (که تغییر یک چیز خودش جزء اثرات جانبی هست)
بعد این جمله را می تونیم ببینیم:
قاعده ۱:
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced
یعنی مثلا در عبارت A + B معلوم نیست که ابتدا A اجرا می شه یا B اجرا می شه
بعد یک جمله دیگه ذکر می کنه:
قاعده ۲:
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.
اما در بخش 5.17 هم در خصوص عملگر انتساب قاعده زیر اومده
قاعده ۳
5.17 In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

در مثالی که شما زدید ار float استفاده کردید که اشیاء scalar به حساب میاد
حالا بگذارید از مثال شما استفاده کنیم:

مثال اول)
x=1.00;
این یک عبارت انتساب هست در اینجا دو تا کار صورت می گیره
۱- محاسبه مقدار (که در اینجا یافتن شناسه یا ادرسی هست که چیزی در آن قرار بگیره یعنی مشخص کردن شناسه یا آدرس x)
2- به علت اینکه در شیء x می خواهد تغییری ایجاد بشه پس اثر جانبی اتفاق می افته
خب اینجا مشکلی نیست چون فقط یک x داریم

مثال دوم)
x+=x++;
اون عملوندی که در سمت چپ عملگر =+ قرار داره دو تا کار روی اون صورت می گیره
۱- محاسبه مقدار (که در اینجا الف) هم شامل یافتن شاسه یا آدرس x هست و ب) هم شامل بیرون کشیدن مقدار ذخیره شده در اون متغیر هست)
۲- اثر جانبی انتساب، که همون تغییر x هست
در سمت راست هم ۲ تا کار صورت می گیره
۱ - محاسبه مقدار (که در اینجا الف) هم شامل یافتن شاسه یا آدرس x هست و ب) هم شامل بیرون کشیدن مقدار ذخیره شده در اون متغیر هست)
۲ - اثر جانبی عملگر ++ که باعث اضافه شدن یکی به x می شه
حالا ما با توجه به قاعده ۱ که گفته «به جز در موارد ذکر شده» در سایر موارد ترتیب برآورد عملوندهای یک عملگر مشخص نیست. و در این مرحله فرض می گیریم که x و ++x با ترتیب نامعین برآورد می شوند اما وقتی به قاعده ۳ نگاه می کنیم که یکی از مصادیق «به جز در موارد ذکر شده» هست می بینیم که گفته فقط «محاسبه مقدار» دو عملوند با ترتیب نامشخص انجام می شه اما «اثر جانبی» عملگر انتساب بعد از محاسبه مقدار دو عملوند انجام می شه و همچنین نگفته اگر مثلا در سمت راست اثر جانبی وجود داشت این اثر جانبی به چه ترتیبی اجرا می شه یعنی ترتیبی برای اثر جانبی سمت راست معین نکرده

در قاعده ۲ گفته اگر اثر جانبی یک شیء نسبت به اثر جانبی همون شیء ترتیبی نداشته باشه ما رفتار تعریف نشده (undefined behavior) داریم .
بررسی اول: در اینجا در سمت چپ یک اثر جانبی داریم (چون داره انتساب صورت می گیره) اما در سمت راست هم اثر جانبی روی x داریم و معلوم نیست که این اثر جانبی قبل از اثر جانبی سمت چپ صورت می گیره یا بعد از اون پس «رفتار تعریف نشده پیش میاد» .
در قاعده ۲ گفته اگر اثر جانبی یک شیء نسبت به محاسبه مقدار ـ که شامل بیرون کشیدن مقدار ـ اون شیءباشه ترتیبی نداشته باشه باز هم رفتار تعریف نشده داریم.
بررسی دوم:در سمت چپ اثر جانبی داریم و در سمت راست بیرون کشیدن مقدار x با توجه به قاعده ۳ قبل از اثر جانبی سمت چپ اتفاق می افته پس رفتار تعریف شده نداریم.
بررسی سم: اما در عین حال سمت راست هم اثر جانبی داریم و چون در براورد سمت چپ هم می اییم یکبار مقدار x را بیرون می کشیم ولی معلوم نیست این بیرون کشیدن مقدار نسبت به اثر جانبی سمت راست چه ترتیبی داره پس «رفتار تعریف نشده پیش میاد» و این برنامه اشتباهه.
بنابراین از ۲ طریق می شه اثبات کرد رفتار تعریف نشده پیش میاد و این برنامه اشتباهه

مثال سوم)
x=x+x++;

بررسی اول:در اینجا در سمت چپ یک اثر جانبی داریم (چون داره انتساب صورت می گیره) اما در سمت راست هم اثر جانبی روی x داریم و معلوم نیست که این اثر جانبی قبل از اثر جانبی سمت چپ صورت می گیره یا بعد از اون پس «رفتار تعریف نشده پیش میاد» .
بررسی دوم: در براورد شدن عبارت سمت راست انتساب یعنی++x+x، با توجه به اینکه قاعده ۲ گفته اگر اثر جانبی یک شیء نسبت به محاسبه مقدار ـ که شامل بیرون کشیدن مقدار ـ اون شیءباشه ترتیبی نداشته باشه باز هم رفتار تعریف نشده داریم توسط ++ یک اثر جانبی داریم در عین حال می خواهیم مقدار x که در سمت چپ عملگر + هست را بیرون بکشیم و اینها نسبت به هم ترتیبی ندارند و رفتار تعریف نشده داریم
بنابراین اینجا هم ما رفتار تعریف نشده داریم و برنامه اشتباهه و از ۲ طریق می شه اثبات کرد که رفتار تعریف نشده پیش میاد.

مثال چهارم)
x=1+(++x);
بررسی اول: در سمت چپ اثر جانبی داریم در سمت راست هم اثر جانبی داریم با توجه به قاعده ۳ که گفته محاسبه مقدار عملوند های عملگر انتساب قبل از عمل انتساب صورت می گیره و برای محاسبه مقدار عملوند x++ لازمه که حتما اثر جانبی اون در ابتدا اجرا بشه و بعد از اون مقدارش محاسبه بشه و وقتی مقدارش محاسبه شد، اثر جانبی در سمت چپ عملگر = انجام می شه بنابراین هم مقدار و هم اثرجانبی دو عملوند با یک ترتیب مشخص انجام می گیره و رفتار تعریف نشده نداریم
بنابراین مثال چهارم کاملا درسته.

مثال پنجم)
x=x+(++x);

برسی اول: در براورد شدن عبارت سمت راست انتساب یعنی++x+x، با توجه به اینکه قاعده ۲ گفته اگر اثر جانبی یک شیء نسبت به محاسبه مقدار ـ که شامل بیرون کشیدن مقدار ـ اون شیءباشه ترتیبی نداشته باشه باز هم رفتار تعریف نشده داریم توسط ++ یک اثر جانبی داریم در عین حال می خواهیم مقدار x که در سمت چپ عملگر + هست را بیرون بکشیم و اینها نسبت به هم ترتیبی ندارند و رفتار تعریف نشده داریم
در اینجا هم رفتار تعریف نشده داریم اما فقط از یک طریق می شه اثبات کرد که همون دلیلی هست که در مثال سوم استفاده شده و این برنامه هم اشتباهه

ASM6502
شنبه 22 خرداد 1395, 18:15 عصر
همون طور که قبلا گفتم واسه تریس کردن این گونه عبارات ترکیبی ظاهرا دباگیر معمولی جواب نمیده یا شاید هم من بلد نیستم.
ولی میشه از دیباگر اسمبلی استفاده کرد که بسیار دقیق نحوه اجرا شدن یه عبارت ترکیبی رو ارائه میده.
واسه این کار اول یه بار F10 رو بزن تا دیباگر معمولی اجرا بشه.
بعد Alt + 8 رو بزن تا دیباگر اسمبلی اجرا بشه.

rahnema1
شنبه 22 خرداد 1395, 19:35 عصر
سلام
واسه این موارد دیباگ و تریس چندان کمکی نمی تونه بکنه.
توی کامپایلر gcc یک گزینه هست به نام -Wsequence-point که باعث می شه وقتی کامپایلر یکی از موارد undefined behavior را پیدا کرد هشدار بده اما این گزینه تمام موارد را نشون نمیده و بعضی موارد را هم درست گزارش نمیده
بهترین گزینه اینه که قواعد ++c را از کتاب استاندارد ++C بخونیم و توسط اون قواعد برنامه ها را تحلیل کنیم. حالا اگه یه وقت حوصله نداشتیم راه ساده تر اینه که هنگام برنامه نویسی از نوشتن عبارتهایی که متغیر در دو طرف یک عملگر تغییر می کنه خودداری کنیم که هم خوانایی برنامه بیشتر می شه و هم احتمال خطا کمتر

mobtadi1
یک شنبه 23 خرداد 1395, 18:30 عصر
سلام
ببینید قواعد مربوط به برآورد شدن عبارات در استاندارد زبان ++C اومده که می تونید در این سایت (https://isocpp.org/std/the-standard) فایل pdf مربوط به آخرین پیش نویسهای این استاندارد را دانلود کنید:
...

سلام
بسیار زیبا و با دقت توضیح دادید؛ و نکته‌ای که بسیار ارزشمنده اینه که با توجه و دقت بسیار به تمام ارسال‌ها و مثال‌هام پاسخ دادید، به جای اینکه یک پاسخ رو بدون برسی تکرار کنید.
متشکرم.

ciavosh
جمعه 25 تیر 1395, 14:22 عصر
ممنون. اما اگر قرار باشه به اینصورت خودم رو توجیه کنم، پس از گذراندن دوره سی، فقط جواب سوالات خودم رو می‌تونم بدم :لبخندساده:
برای من این پاسخ قانع کننده نیست؛ اگرچه شاید پاسخ شما درست باشه.

امیدوارم اگر کاربری توضیح دیگه‌ای داره ارسال کنه.
مرسی.
دوست عزیز برای این که متوجه اشتباه خودتون بشید باید بتونید کد رو به اصطلاح trace یا دنبال کنید. در این روش فرد خودش رو جای کامپیوتر قرار میده و دستورات رو یکی یکی اجرا میکنه. پاسخ ASM6502 استفاده از همین روش است. من هم در ابتدا متوجه نشدم چرا پاسخ ۴ شده ولی وقتی پاسخ ASM6502 رو خوندم متوجه اشتباهمون شدم. x++ به x یکی اضافه میکنه و معادل x+=1 هست پس طبیعتاً مقدار خروجی یکی از مقدار مورد انتظار ما بیشتر میشه.