درود!
این جا مکانی است ویژه برای دانشجویان مهندسی کامپیوتر / آی تی و نرم افزار و صد البته افرادی که جویندگان دانش و تکنولوژی هستند.
آقایان دانوش ،یاشار و آمالی دارندگان این بلاگ بودند و هم اکنون تنها آقای دانوش مدیریت این وبلاگ را بر عهده دارد، با توجه به زمان بندی ها هم اکنون در این سایت فعالیت پویا ای نداریم.

فرق ++a با a=a+1 و....

چهارشنبه 22 آبان 1392
20:25
دانوش پیچگاه
اگر در محیط توربو سی پلاس پلاس برنامه ای بدینگونه بنویسیم:

int A=0;
A=A+1;
cout<<A;

همانطور که انتظار داریم، عدد یک را چاپ میکند. زیرا مقدار اولیه حرف که صفر بود بعلاوه یک شد و سپس چاپ شد.
اما دستور a=a+1 فرقی با ++a ندارد. پس می توان نوشت:
int A=0;
A++;
cout<<A;
که باز هم نتیجه پیشین را خواهیم دید یعنی A=1.

اما اگر به جای ++A اینبار بنویسیم:
int A=0, B=0;
B=A++;
cout<<A;
cout<<B;
می بایستی که A=1 و B=1 باشد. پس مشکلی تا اینجا نباید باشد. اما این طور نیست و خواهیم دید A=0 و B=1 خواهد بود! اما چرا؟ در ادامه خواهیم دید چگونه و چرا این طور می شود.
در حقیقت ما چند دستور برای اضافه کردن یک واحد به متغییر داریم؛ فرض می کنیم a متغییر ما باشد. راه های موجودی در ++C چنین هستند:
  1. a = a+1
  2. a++
  3. ++a
  4. a = ( a += 1)

می توان جای + را با - تغییر داد تا واحد ها کم شوند. ما در اینجا برای راحتی کار + را مورد توجه داریم.

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

روش های 1،3و4 همه به یک نوع کاراضافه کردن واحد را انجام میدهند و اثبات این کار در پایان این پست موجود است. اما در روش 2 که ++a است، متغییر حالت ابتدایی خود را تنها در زمانی که معادل یک متغییر دیگر نباشد تغییر می دهد و کاملاً شبیه روش های 1،3و4 عمل میکند. اما زمانی که یک عمل گر یا Operator  همراه دستور ++a باشد داستان تغییر می کند و متغییر مقدار اولیه خود را (که صفر بود) حفظ می کند اما مقدار اضافه شده و نهایی را به متغییر عمل شده نسبت می دهد. در مثال و روش های بالا از عمل گر استفاده نشده بود؛ هم اکنون چند مثال از حالتی که از عملگر استفاده شده را خواهید دید.


اما قبل از دیدن مثال باید بدانیم اصلاً عملگر چیست؟

عملگر در حقیقت همان عبارت *=a هست که * در آن مقداری است نسبت می دهیم و a مقداری است که کاربر به کامپیوتر فهماند.


و اما مثال:

  1. b=a=a+1
  2. b=a++
  3. b=++a
  4. b=a=(a+=1)

!نکنه مهم

هم حالت 2 و هم حالت 3 هردو عملگر دارند ولی همانطور که گفته شد نتایج حالات 1 و 3 و 4 با حالت 2 متفاوت است، چرا؟

برای اینکه در حالت 3 و باقی حالات به جز حالت 2؛ مقدار اولیه a یکی اضافه می شود و مقدار نهایی a به علاوه یک نمایش داده می شود اما در حالت دوم؛ به مقدار اولیه a یکی اضافه می شود اما مقدار نهایی برای مقدار b  نسبت داده می شود و مقدار a همان مقدار نخستین آن که 0 بود؛ می ماند. اما چرا؟

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

(a++) (متفاوت با بقیه)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    mov    -0x8(%rbp),%eax
   0x00000000004004c2 <+14>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c5 <+17>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq
End of assembler dump.


(++a)

(gdb) disassemble foo Dump of assembler code for function foo:
0x00000000004004b4 <+0>: push %rbp
0x00000000004004b5 <+1>: mov %rsp,%rbp
0x00000000004004b8
<+4>: movl $0x0,-0x8(%rbp)
0x00000000004004bf
<+11>: addl $0x1,-0x8(%rbp)
0x00000000004004c3 <+15>: mov -0x8(%rbp),%eax
0x00000000004004c6
<+18>: mov %eax,-0x4(%rbp)
0x00000000004004c9 <+21>: pop %rbp
0x00000000004004ca
<+22>: retq End of assembler dump.


(a += 1)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump


(a = a + 1)

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004b4 <+0>:     push   %rbp
   0x00000000004004b5 <+1>:     mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     movl   $0x0,-0x8(%rbp)
   0x00000000004004bf <+11>:    addl   $0x1,-0x8(%rbp)
   0x00000000004004c3 <+15>:    mov    -0x8(%rbp),%eax
   0x00000000004004c6 <+18>:    mov    %eax,-0x4(%rbp)
   0x00000000004004c9 <+21>:    pop    %rbp
   0x00000000004004ca <+22>:    retq   
End of assembler dump.

این بلاگ را برای خواندن مطالب مربوط به مهندسی فناوری اطلاعات به دیگران پیشنهاد دهید.





شبکه اجتماعی فارسی کلوب | Buy Mobile Traffic | سایت سوالات