I = 0 এর জন্য, (i + = i ++) 0 এর সমান কেন?


253

নিম্নলিখিত কোডটি নিন (কনসোল অ্যাপ্লিকেশন হিসাবে ব্যবহারযোগ্য):

static void Main(string[] args)
{
    int i = 0;
    i += i++;
    Console.WriteLine(i);
    Console.ReadLine();
}

ফলাফলটি i০. আমি প্রত্যাশা করি ২ (যেমনটি আমার কয়েকজন সহকর্মী করেছেন)। সম্ভবত সংকলক কিছু ধরণের কাঠামো তৈরি করে যার ফলশ্রুতি iশূন্য।

আমার প্রত্যাশা 2 হওয়ার কারণটি হ'ল, আমার চিন্তার ধারায় ডান হাতের বিবৃতিটি প্রথমে মূল্যায়ন করা হবে এবং i দিয়ে 1 বৃদ্ধি করা হবে Than যেহেতু আমি ইতিমধ্যে 1, তাই এটি 1 থেকে 1 যোগ করছে So সুতরাং 1 + 1 = 2. স্পষ্টতই যা ঘটছে তা নয়।

সংকলকটি কী করে বা রানটাইমে কী ঘটে তা আপনি ব্যাখ্যা করতে পারেন? ফলাফল শূন্য কেন?

কিছু ধরণের দাবি অস্বীকার: আমি পুরোপুরি সচেতন আপনি এই কোডটি ব্যবহার করবেন না (এবং সম্ভবত করা উচিত নয়)। আমি জানি আমি কখনই করব না। যাইহোক, আমি কেন এটি এমনভাবে কাজ করে এবং ঠিক কী ঘটছে তা জানতে আগ্রহী interesting


57
প্রত্যাশিত ফলাফল 1 হওয়া উচিত নয়? i (0) + = i ++ (1) অতএব 0 + = 1 = 1
বর্ষণ

11
এটি প্রত্যাশার মতো কাজ করে
স্টিভ

177
এই প্রশ্নটির কতগুলি প্রকরণ জিজ্ঞাসা করা হচ্ছে?
mowwwalker

20
প্রেজেন্ট্রিমেন্টেশন মানটি বাড়ানোর আগে i + = ++ আমি আপনাকে 1 দিয়ে দেব
পিয়ারলুক এসএস

21
কেন সকলেই প্রাক-বনাম পোস্টকেনক্রমেন্টে মনোনিবেশ করছে? "অদ্ভুত" জিনিস যে মান এর iবাম দিকে +=ডানদিকে আগে "ক্যাশে" হয় মূল্যায়ন করা হয়। এটি পাল্টা স্বজ্ঞাত, যেমন এটি যেমন iকোনও বস্তু হয় তবে একটি অনুলিপি অপারেশন প্রয়োজন । (দয়া করে আমাকে ভুল বুঝবেন না: আমি 0এটিকে সঠিক এবং মানসম্মত উত্তর বলে উল্লেখ করতে একেবারেই সম্মত ))
জনবি

উত্তর:


425

এই:

int i = 0;
i += i++

আপনি করছেন হিসাবে দেখা যেতে পারে (নিম্নলিখিতটি একটি স্থূল ওভারসিম্প্লিফিকেশন):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

আসলে কী ঘটে তার চেয়ে বেশি জড়িত - এমএসডিএন, 7.5.9 পোস্টফিক্স ইনক্রিমেন্ট এবং হ্রাস অপারেটরগুলি একবার দেখুন :

এক্স ++ বা x- ফর্মের পোস্টফিক্স ইনক্রিমেন্ট বা হ্রাস ক্রিয়াকলাপের রানটাইম প্রক্রিয়াকরণে নিম্নলিখিত পদক্ষেপগুলি রয়েছে:

  • যদি এক্সকে ভেরিয়েবল হিসাবে শ্রেণীবদ্ধ করা হয়:

    • পরিবর্তনশীল উত্পাদনের জন্য এক্স মূল্যায়ন করা হয়।
    • এক্স এর মান সংরক্ষণ করা হয়।
    • নির্বাচিত অপারেটরটিকে তার আর্গুমেন্ট হিসাবে x এর সংরক্ষিত মানের সাথে ডাকা হয়।
    • অপারেটরের ফিরিয়ে দেওয়া মান x এর মূল্যায়নের দ্বারা প্রদত্ত স্থানে সংরক্ষণ করা হয়।
    • এক্স এর সংরক্ষিত মান অপারেশনের ফলাফল হয়ে যায়।

লক্ষ্য করুন কারণে পূর্ববর্তিতার ক্রম , পোস্টসাফিক্স ++ঘটে সামনে += কিন্তু আপ অব্যবহৃত হচ্ছে ফলাফলের প্রান্ত (পূর্ববর্তী মান হিসাবে iব্যবহার করা হয়)।


একটি আরো পুঙ্খানুপুঙ্খ পচানি i += i++অংশের এটা তৈরি করা হয় জানি যে উভয় এক প্রয়োজন +=এবং ++পারমাণবিক নয় (যে, তন্ন তন্ন এক একটি একক অপারেশন), এমনকি যদি তারা চেহারা তারা মত। এগুলি যেভাবে প্রয়োগ করা হয় তাতে অস্থায়ী ভেরিয়েবলগুলি জড়িত থাকে, iঅপারেশনগুলি হওয়ার আগে এর অনুলিপি - প্রতিটি ক্রিয়াকলাপের জন্য একটি। (আমি নাম ব্যবহার করবে iAddএবং iAssignঅস্থায়ী জন্য ব্যবহৃত ভেরিয়েবলের জন্য ++এবং +=যথাক্রমে)।

সুতরাং, যা ঘটছে তার নিবিড় সংক্ষেপণ হ'ল:

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;

3
@ ওজেড বিবৃতিটির মূল্যায়ন ++শেষ হওয়ার আগে অপারেশন করা হবে । সুতরাং +=মানটি ওভাররাইট করে। এই কি ঘটেছে?
অনিরুধ রমনাথন

6
আসলে তার @Oded: int i = 0; i = i + 1; (postfix) i = 0; (assignment)। আপনি যদি সেই বিবৃতিতে অন্য কোথাও ব্যবহার করেন তবে এটি 1 টির সময় মূল্যায়ন করবে।
ড্রচ

@ চথুলহু - মূলতঃ উত্তর দ্বারা dtb বিস্তারিত মধ্যে যায়।
ওডে

6
আমি এটি কিনে নেই @ ইয়োরির উত্তর অনেক বেশি নির্ভুল। একটির জন্য, আপনার উত্তরে আপনি বলেছিলেন যে শেষ লাইনটি i+1হওয়া উচিত ছিল i=i+1। কি তাই না i++?
24:32

3
উত্তরের প্রথম অংশটি অপ্রয়োজনীয়। আপনার শেষ কোড নমুনা এটি IMHO করতে পারে। যদিও +1
কোরাজা 26

194

চলমান কোডটি বিযুক্ত করা:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

সমান কোড

এটি নিম্নলিখিত কোডের মতো একই কোডটিতে সংকলন করে:

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

দ্বিতীয় কোডটি বিচ্ছিন্ন করা (কেবল সেগুলি একই প্রমাণ করার জন্য)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

অপ্রয়োজনীয় উইন্ডোটি খুলছে

বেশিরভাগ লোকেরা জানেন না, এমনকি মনে রাখবেন না যে তারা ভিজ্যুয়াল স্টুডিও বিচ্ছিন্ন উইন্ডোটি ব্যবহার করে চূড়ান্ত ইন-মেমরি অ্যাসেম্বলি কোডটি দেখতে পারে । এটি কার্যকর করা হচ্ছে এমন মেশিন কোডটি দেখায়, এটি সিআইএল নয়।

ডিবাগ করার সময় এটি ব্যবহার করুন:

Debug (menu) -> Windows (submenu) -> Disassembly

তাহলে পোস্টফিক্স ++ নিয়ে কী হচ্ছে?

পোস্টফিক্স ++ বলছে যে আমরা মূল্যায়নের পরে অপারেন্ডের মান বাড়িয়ে তুলতে চাই ... যে প্রত্যেকে জানে ... যা কিছুটা বিভ্রান্ত করে তা হল "মূল্যায়নের পরে" এর অর্থ ।

সুতরাং "মূল্যায়ন শেষে" এর অর্থ কী:

  • একই কোডের লাইনে অপারেন্ডের অন্যান্য ব্যবহারগুলি অবশ্যই প্রভাবিত হবে:
    • a = i++ + i দ্বিতীয়টি আমি ইনক্রিমেন্ট দ্বারা প্রভাবিত
    • Func(i++, i) দ্বিতীয় আমি প্রভাবিত হয়
  • একই লাইনে থাকা অন্যান্য ব্যবহারগুলি শর্ট সার্কিট অপারেটরের সম্মান করে ||এবং &&:
    • (false && i++ != i) || i == 0 তৃতীয় আমি আই ++ দ্বারা প্রভাবিত হয় না কারণ এটি মূল্যায়ন করা হয় না

তাই অর্থ কি: i += i++;?

এটা যেমন হয় i = i + i++;

মূল্যায়নের ক্রমটি হ'ল:

  1. আই + আই সঞ্চয় করুন (এটি 0 + 0)
  2. বৃদ্ধি i (আমি 1 হয়ে)
  3. পদক্ষেপের 1 এর মান নির্ধারণ করুন i (আমি 0 হয়ে)

বর্ধন বাতিল করা হচ্ছে না এমন নয়।

মানে কি: i = i++ + i;?

এটি আগের উদাহরণের মতো নয়। 3 য় iবর্ধিত দ্বারা প্রভাবিত হয়।

মূল্যায়নের ক্রমটি হ'ল:

  1. আই সঞ্চয় করুন (এটি 0)
  2. বৃদ্ধি i (আমি 1 হয়ে)
  3. ধাপ 1 + i এর স্টোর মান (এটি 0 + 1)
  4. পদক্ষেপ 3 থেকে i এর মান নির্ধারণ করুন (আমি 1 হয়ে যাই)

22
নিখরচায় হার্ডকোর বিচ্ছুরণের জন্য + 1 ++। চক নরিস গর্বিত হবেন :) আমার ধারণা আপনি এই ধারণাটি করেছেন যে ওপি ইন্টেলের উপর রয়েছে, যদিও কোনও মনো বন্দর নয় ...
স্টুয়ার্টএলসি

19
সি # এর অভিব্যক্তির জন্য একটি নির্ধারিত মূল্যায়ন আদেশ রয়েছে এবং অবজেক্ট কোড কেবল সেই আদেশটি প্রয়োগ করে। মেশিন কোড আউটপুট মূল্যায়ন আদেশের কারণ বা ব্যাখ্যা নয়।
কাজ

8
যন্ত্রের কোডটি মূল্যায়নের ক্রম কীভাবে আইএমও বাস্তবায়িত হয় তা বোঝা সহজ করে তোলে।
কেভিন

5
@ স্টুয়ার্টএলসি আমি দেখছি আপনি সেখানে কী করেছেন। যদিও এটি বাতিল করা আপভোট সম্পর্কে লজ্জাজনক।
স্টিফান ডোনাল

2
a++ + aa + a++কারণ এটি আর খাঁটি গণিত নয় the বীজগণিতের সামঞ্জস্যতা আইনটি এই অভিব্যক্তিটির মধ্য দিয়ে ভেরিয়েবলের মান পরিবর্তন করার সম্ভাবনাটি বিবেচনায় নেয় না। যখন প্রোগ্রামিং কার্যকরী প্রোগ্রামিং হয় তখন গণিতে কেবল ঝরঝরে প্রোগ্রামিংয়ের মানচিত্র হয়। এবং তবুও না, প্রতিনিধিত্বমূলক সীমাবদ্ধতার কারণে। উদাহরণস্বরূপ ভাসমান-পয়েন্ট সংখ্যাগুলি কখনও কখনও বাস্তবের মতো আচরণ করে এবং কখনও কখনও তা করে না। এমনকি পার্শ্ব প্রতিক্রিয়া, যোগাযোগ ব্যবস্থা এবং সাহসিকতা আইনগুলি ছাড়াই যা ভাসমান-পয়েন্ট সংখ্যাগুলিতে গণিতের বিরতিতে আসল সংখ্যায় প্রযোজ্য।
কাজ

61
int i = 0;
i += i++;

নিম্নলিখিত হিসাবে মূল্যায়ন করা হয়:

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

অর্থাত্ iদু'বার পরিবর্তন করা হয়েছে: একবার i++প্রকাশ দ্বারা এবং একবার +=বিবৃতি দ্বারা ।

তবে +=বিবৃতিটির অপারেশনগুলি হ'ল

  • iমূল্যায়নের আগে i++(বাম দিকে +=) এর মান এবং
  • iমূল্যায়নের আগে মান i++(ডান দিকের দিকের +=)।

আহ এটি একটি দুর্দান্ত ব্যাখ্যা। বিপরীত পলিশ স্বরলিপি ব্যবহার করে যখন আমি স্ট্যাক ভিত্তিক ক্যালকুলেটরে কাজ করেছি তখন আমাকে মনে করিয়ে দেয়।
নাথান

36

প্রথমত, i++আয় 0. তারপর i1. সর্বশেষে দ্বারা মান বৃদ্ধি হয় iপ্রাথমিক মান সেট করা হয় iযা 0 প্লাস মান i++ফিরে, যা শূন্য অত্যধিক। 0 + 0 = 0।


2
তবে এটি i += i++;নয় i = i++;, সুতরাং i++(0) এর মান যুক্ত হয় iএবং " প্রত্যাবর্তিত iমানকে সেট করা হয় না i++"। এখন প্রশ্ন হল, যখন মানটি i++ফেরত iআসবে iতখন বাড়ানো মান হবে বা বর্ধিত মান হবে না? উত্তর, আমার বন্ধু, চশমা লেখা হয়।
ড্যানিয়েল ফিশার

সত্য, আমি এটি ঠিক করব। কিন্তু যাই হোক যেহেতু i = 0প্রথমে i += somethingসমতুল্য হয় i = 0 + somethingযা i = something
জং

32

এটি কেবল বাম থেকে ডানে, বিমূর্ত সিনট্যাক্স ট্রিটির নীচের অংশের মূল্যায়ন। ধারণামূলকভাবে, অভিব্যক্তির গাছটি নীচ থেকে নীচে থেকে হাঁটা হয়, তবে পুনরাবৃত্তিটি নীচে থেকে গাছটিকে ব্যাক আপ করার সাথে সাথে মূল্যায়ন উদ্ঘাটিত হয়।

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

মূল নোড বিবেচনা করে মূল্যায়ন শুরু হয় +=। এটাই হল অভিব্যক্তির প্রধান উপাদান। +=আমরা যেখানে ভেরিয়েবলটি সঞ্চয় করি তা নির্ধারণ করতে এবং পূর্বের মানটি শূন্যের জন্য অবশ্যই বাম অপারেন্ডকে মূল্যায়ন করতে হবে। এরপরে, ডান দিকটি মূল্যায়ন করতে হবে।

ডান দিকটি একটি পোস্ট-ইনক্রিমেন্টিং ++অপারেটর। এটির একটি অপরেনড রয়েছে, iযা একটি মানের উত্স হিসাবে এবং মূল্য সঞ্চয় করতে হয় এমন জায়গা হিসাবে উভয়ই মূল্যায়ন করা হয়। অপারেটর মূল্যায়ন করে i, খুঁজে বের করে 0এবং ফলস্বরূপ একটি 1সেই স্থানে সংরক্ষণ করে। এটি পূর্বের মানটি ফেরত দেওয়ার 0শব্দার্থক অনুসারে পূর্বের মানটি প্রদান করে।

এখন নিয়ন্ত্রণ আবার +=অপারেটরের কাছে ফিরে আসে । এটির ক্রিয়াকলাপটি শেষ করার জন্য এখন সমস্ত তথ্য রয়েছে। এটি ফলাফল (সঞ্চয়স্থানের অবস্থান i) পাশাপাশি পূর্বের মানটি কোথায় সংরক্ষণ করতে পারে তা এবং এটির পূর্বের মানটিতে যুক্ত করার মান রয়েছে, যথা 0। সুতরাং, iশূন্য দিয়ে শেষ হয়।

জাভার মতো, সি # মূল্যায়নের ক্রম স্থির করে সি ভাষার একটি খুব অ্যাসিনাইন দিকটি স্যানিটাইজ করেছে। বাম থেকে ডান, নীচে আপ: সর্বাধিক সুস্পষ্ট ক্রম যা কোডারদের দ্বারা প্রত্যাশিত।


+1: প্রতিটি কোডার যে আশা করে তা ছাড়া আমি আপনার সাথে একমত হই ... আমি আশা করি এটি এর মতো কিছু হবে: SetSum(ref i, Inc(ref i))সহ int SetSum(ref int a, int b) { return a += b; }এবং int Inc(ref int a) { return a++; }... অবশ্যই আমি এর চেয়ে বেশি আশা করি না।
মিগুয়েল অ্যাঞ্জেলো

এছাড়াও, আমি যা প্রত্যাশা করলাম তা বেমানান! এটি এবং এর Set(ref i, Sum(i, Inc(ref i)))সাথে সমান হবে না । int Set(ref int a, int b) { return a = b; }int Sum(int a, int b) { return a + b; }
মিগুয়েল অ্যাঞ্জেলো

ধন্যবাদ; আপনি আমার উত্তরের একটি ত্রুটি / অসম্পূর্ণতার দিকে ইঙ্গিত করেছেন যা আমাকে ঠিক করতে হবে।
কাজ

সমস্যাটি SetSumহ'ল এটি বাম অপারেন্ডকে মূল্যায়ন করে না i, তবে কেবল তার ঠিকানা নেয়, সুতরাং এটি অপারেন্ডের সম্পূর্ণ বাম থেকে ডান মূল্যায়নের সমতুল্য নয়। আপনার মতো কিছু দরকার SetSum(ref i, i, PostInc(ref i))। এর দ্বিতীয় যুক্তি SetSumহ'ল মানটি যুক্ত করা হবে, যেখানে আমরা কেবল iপূর্বের মানটি নির্দিষ্ট করতে ব্যবহার করি iSetSumঠিক হয় int SetSum(ref int dest, int a, int b) { return dest = a + b; }
কাজ

বিভ্রান্তি ঘটে (কমপক্ষে আমার জন্য) + = অপারেটরের সাথে, কারণ অ্যাসাইনমেন্ট অপারেটরের ডান থেকে বামে মূল্যায়ন থাকে (যেমন a = b = c = d) ... সুতরাং যে কেউ ধারণা করতে পারেন যে + = একই নিয়ম অনুসরণ করে, পারমাণবিক অপারেশন হিসাবে (যেমনটি আমি আমার সেটসাম পদ্ধতিটি দিয়েছিলাম) ... তবে বাস্তবে যা ঘটে তা হ'ল সি # অনুবাদ a += bকরে a = a + b... এটি দেখায় যে + = অপারেটরটি পারমাণবিক নয় ... এটি কেবল সিনট্যাকটিক চিনি।
মিগুয়েল অ্যাঞ্জেলো

30

কারণ i++প্রথমে মানটি ফেরত দেয়, তারপরে এটি বৃদ্ধি করে। তবে আমি 1 এ সেট হওয়ার পরে, আপনি এটি 0 এ সেট করেছেন।


17

পোস্ট-ইনক্রিমেন্ট পদ্ধতিটি এরকম কিছু দেখাচ্ছে

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

তাই মূলত আপনি কল যখন i++, iবৃদ্ধি কিন্তু মূল মান আপনার ক্ষেত্রে ফিরিয়ে দেওয়া হয় এটা 0 ফিরে হচ্ছে।



12

i ++ এর অর্থ হল: আমি তার মান বাড়িয়ে দেব।

i + = i ++ এর অর্থ: i এর বর্তমান মানটি নিন। আই ++ এর ফলাফল যুক্ত করুন।

এখন, আসুন শর্ত হিসাবে i = 0 যুক্ত করুন। i + = i ++ এখন এর মতো মূল্যায়ন করা হয়:

  1. আমার বর্তমান মান কত? এটি 0। এটি সংরক্ষণ করুন যাতে আমরা এটিতে ++ এর ফলাফল যুক্ত করতে পারি।
  2. আই ++ মূল্যায়ন করুন (0 এ মূল্যায়ন করুন কারণ এটিই আমার বর্তমান মান)
  3. সঞ্চিত মান লোড করুন এবং এতে দ্বিতীয় ধাপের ফলাফল যুক্ত করুন। (0 থেকে 0 যোগ করুন)

দ্রষ্টব্য: দ্বিতীয় ধাপের শেষে, i এর মানটি আসলে 1। তবে, পদক্ষেপ 3-এ, আপনি i এর মান বাড়ানোর আগে লোড করে এটিকে বাতিল করবেন।

আই ++ এর বিপরীতে, ++ আমি বর্ধিত মান প্রদান করে।

সুতরাং, i + = ++ আমি আপনাকে 1 দেব would


এটি সম্পূর্ণ সহায়তা
পুত্রসভা

11

পোস্ট ফিক্স ইনক্রিমেন্ট অপারেটর, ++ভেরিয়েবলকে এক্সপ্রেশন-তে একটি মান দেয় এবং তারপরে আপনি যে ইনক্রিমেন্টটি বরাদ্দ করেছিলেন তা শূন্য (0) মানটি ফেরত দেয় iযা বর্ধিত এক (1) ওভাররাইট করে , তাই আপনি শূন্য হয়ে যাচ্ছেন। আপনি ++ অপারেটর (এমএসডিএন) এ ইনক্রিমেন্ট অপারেটর সম্পর্কে আরও পড়তে পারেন ।


8

i += i++;সমান হবে শূন্য, কারণ এটি ++পরে করে।

i += ++i; আগে এটা করবে


4
যদি এটি ++পরে হয়, আমি ফলাফলটি আশা করব 1
comecme

8

++ পোস্টফিক্স iএটি বাড়ানোর আগে মূল্যায়ন করে এবং +=কেবল iএকবার মূল্যায়ন করে ।

অতএব, 0 + 0 = 0, যেমন iবর্ধিত হওয়ার আগে মূল্যায়ন করা হয় এবং ব্যবহৃত হয়, যেমন পোস্টফিক্স বিন্যাসটি ++ব্যবহৃত হয়। প্রথমে iবর্ধিত হওয়ার জন্য উপসর্গ ফর্মটি ব্যবহার করুন ( ++i)।

(এছাড়াও, কেবল একটি নোট: আপনার 0+ (0 + 1) = 1 হিসাবে কেবল 1 পাওয়া উচিত)

তথ্যসূত্র: http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+ =)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)


8

সি # কী করছে, এবং বিভ্রান্তির "কেন"

আমি মানটি 1 হওয়ারও আশা করেছিলাম ... তবে এই বিষয়ে কিছু অনুসন্ধান কিছু পয়েন্ট পরিষ্কার করেছে।

নিম্নলিখিত পদ্ধতিগুলি কসাইডার করুন:

    static int SetSum(ref int a, int b) { return a += b; }

    static int Inc(ref int a) { return a++; }

আমি প্রত্যাশা করেছি যে i += i++একই রকম হবে SetSum(ref i, Inc(ref i))। এই বিবৃতিটির পরে i এর মান 1 :

int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1

তবে আমি অন্য সিদ্ধান্তে পৌঁছলাম ... i += i++আসলে একইরকম i = i + i++... তাই এই ফাংশনগুলি ব্যবহার করে আমি আরও একটি অনুরূপ উদাহরণ তৈরি করেছি:

    static int Sum(int a, int b) { return a + b; }

    static int Set(ref int a, int b) { return a = b; }

এটিকে ফোন করার পরে Set(ref i, Sum(i, Inc(ref i)))আমার মান 0 :

int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0

এটি কেবল সি # কী করছে তা ব্যাখ্যা করে না ... তবে কেন আমাকে প্রচুর পরিমাণে লোক এতে বিভ্রান্ত করেছিল।


2
দয়া করে এটি আপনার আসল উত্তরে যুক্ত করুন, এটি পৃথক উত্তর হিসাবে কোনও লাভ যুক্ত করে না।
ক্যাস্পারওন

2
আমি এটি অন্য উত্তরটিকে কলুষিত না করার জন্য করেছি, কারণ এটি বিবর্তিত কোড সম্পর্কে ... এই উত্তরটিতে থাকাকালীন, আমি বিষয়গুলি ব্যাখ্যা করার জন্য একটি ভিন্ন পদ্ধতির চেষ্টা করেছি। আপনি কি মনে করেন? আমি কি অন্য উত্তরটি সম্পাদনা করে এটিকে যুক্ত করব? হতে পারে, এটিকে প্রিপেন্ড করুন ... জানেন না! পরামর্শের জন্য ধন্যবাদ!
মিগুয়েল অ্যাঞ্জেলো

7

একটি ভাল স্মৃতিবিদ্যার বিষয়টি আমি সবসময় মনে করি এটি নিম্নলিখিত:

যদি অভিব্যক্তির পরে++ দাঁড়িয়ে থাকে তবে এটি আগের মানটি দেয় । সুতরাং নিম্নলিখিত কোড

int a = 1;
int b = a++;

এটি 1, কারণ এটি পরে স্থির দ্বারা বৃদ্ধি পাওয়ার আগেa 1 ছিল । লোকেরা এই পোস্টটিকে ফিক্স স্বরলিপি বলে। একটি প্রাক ফিক্স স্বরলিপিও রয়েছে, যেখানে জিনিসগুলি একেবারে বিপরীত: যদি সামনে দাঁড়িয়ে থাকে তবে অভিব্যক্তিটি অপারেশনের পরে যে মানটি দেয় তা ফিরিয়ে দেয় :++ a++

int a = 1;
int b = ++a;

b এখানে দুটি।

সুতরাং আপনার কোডের জন্য, এর অর্থ

int i = 0;
i += (i++);

i++0 প্রদান করে (উপরে বর্ণিত হিসাবে), তাই 0 + 0 = 0

i += (++i); // Here 'i' would become two

স্কট মায়ার্স "কার্যকর সি ++ প্রোগ্রামিং" এ দুটি স্বীকৃতির মধ্যে পার্থক্য বর্ণনা করেছেন। অভ্যন্তরীণভাবে i++(পোস্টফিক্স) মানটি মনে করে iএবং প্রিফিক্স-নোটেশন ( ++i) ডাকে এবং পুরানো মানটি ফেরত দেয় i,। এই জন্যই তুমি সর্বদা ব্যবহার করা উচিত ++iমধ্যে forলুপ (যদিও আমি মনে করি সব আধুনিক কম্পাইলার অনুবাদ করছেন i++করার ++iমধ্যে forলুপ)।


1
আমি পরীক্ষা করেছি int i = 0; i += (++i), এবং iদু'জনের পরিবর্তে একটিতে সেট করা আছে। এটা তোলে পোস্টসাফিক্স পরিবর্তে উপসর্গ ব্যবহার সত্য যে, যদি আপনি লিখতে পরিবর্তন করে না যেহেতু খুব আমার কাছে জ্ঞান করে তোলে, i += (++i)আউট i = i + (++i), iআগে মূল্যায়ন করা হয় ++i, যার ফলে i = 0 + (++i)অবশেষে i = 0 + 1
ওয়াটজ

6

আপনার প্রশ্নের সঠিক উত্তর যা সঠিক তা হ'ল: কারণ এটি অপরিজ্ঞাত।

ঠিক আছে, আপনারা সবাই আমাকে জ্বালানোর আগে ..

আপনি সকলেই উত্তর দিয়েছেন কেন i+=i++ফলাফলটি সঠিক এবং যৌক্তিক i=0

আপনার উত্তরগুলির প্রতি 1 টিতে ভোট নেওয়ার জন্য আমি প্রলুব্ধ হয়েছিলাম তবে আমি যে সুনামের অঙ্ক করেছি তা খুব বেশি হবে ..

আমি কেন আপনাদের প্রতি এত পাগল? আপনার উত্তরগুলি যা ব্যাখ্যা করে তার জন্য নয় ..
আমার অর্থ, আমি যে প্রতিটি উত্তর পড়েছি তা অসম্ভবকে ব্যাখ্যা করার জন্য একটি দুর্দান্ত প্রচেষ্টা করেছিল, আমি সাধুবাদ!

তবে ফলাফল কী ?? এটি কি স্বজ্ঞাত ফলাফল - এটি গ্রহণযোগ্য ফলাফল ??

আপনার প্রত্যেকে "নগ্ন রাজা" দেখেছেন এবং কোনওরকমে এটিকে যুক্তিযুক্ত রাজা হিসাবে গ্রহণ করেছেন।

আপনারা সবাই ভুল!

i+=i++;ফলাফল 0অনির্ধারিত হয়।

ভাষা মূল্যায়ন ব্যবস্থায় একটি বাগ আপনি করতে পারেন .. বা আরও খারাপ! নকশায় একটি বাগ।

একটি প্রমাণ চান? অবশ্যই আপনি চান!

int t=0; int i=0; t+=i++; //t=0; i=1

এখন এটি ... স্বজ্ঞাত ফলাফল! কারণ আমরা প্রথমে tএটিকে একটি মান সহ নির্ধারিত মূল্যায়ন করেছিলাম এবং কেবল মূল্যায়ন ও অ্যাসাইনমেন্টের পরে আমাদের পোস্ট অপারেশনটি ঘটেছিল - যুক্তিযুক্ত তাই না?

এটি কি যুক্তিযুক্ত: i=i++এবং i=iএকই ফলাফল প্রদান করে i?

যখন t=i++এবং t=iজন্য বিভিন্ন ফলাফল i

পোস্ট অপারেশন এমন কিছু যা বিবৃতি মূল্যায়নের পরে হওয়া উচিত।
অতএব:

int i=0;
i+=i++;

আমরা লিখলে একই হওয়া উচিত:

int i=0;
i = i + i ++;

এবং তাই হিসাবে একই:

int i=0;
i= i + i;
i ++;

এবং তাই হিসাবে একই:

int i=0;
i = i + i;
i = i + 1;

1আমরা যদি যুক্তিবাদী চিন্তাভাবনা নিয়ে চলি তবে কম্পাইলারের মধ্যে কোনও বাগ বা ভাষার নকশায় একটি বাগ নির্দেশ করে না এমন ফলাফল - তবে এমএসডিএন এবং অন্যান্য অনেক উত্স আমাদের বলে "ওহে - এটি অপরিজ্ঞাত!"

এখন আমি চালিয়ে যাওয়ার আগে, আমি যে উদাহরণ দিয়েছি সেগুলির এই সেটটি কেউ সমর্থন করে বা স্বীকৃত নয় .. তবে স্বজ্ঞাত এবং যুক্তিযুক্ত পদ্ধতি অনুসারে এটিই এর ফলস্বরূপ হওয়া উচিত ছিল।

কোডারকে কীভাবে সমাবেশটি লেখা বা অনুবাদ করা হচ্ছে তা সম্পর্কে কোনও জ্ঞান থাকা উচিত নয়!

যদি এটি এমনভাবে লেখা হয় যা ভাষার সংজ্ঞাগুলিকে সম্মান করবে না - এটি একটি বাগ!

এবং শেষ করতে আমি উইকিপিডিয়া, বর্ধন এবং হ্রাস অপারেটরগুলি
থেকে এটি অনুলিপি করেছি : যেহেতু বর্ধিত / হ্রাস অপারেটর তার অপারেন্ডকে পরিবর্তন করে, একই অভিব্যক্তির মধ্যে একাধিকবার এমন অপারেন্ড ব্যবহার অনির্ধারিত ফলাফল আনতে পারে । উদাহরণস্বরূপ, এক্স - ++ এক্স এর মত প্রকাশে, বিয়োগ বা বর্ধন অপারেটরগুলি কোন ক্রমটি করা উচিত তা পরিষ্কার নয়। সংকলক দ্বারা যখন অপ্টিমাইজেশন প্রয়োগ করা হয় তখন এর মতো পরিস্থিতি আরও খারাপ হয়, যার ফলস্বরূপ ক্রিয়াকলাপের উদ্দেশ্য অনুসারে ক্রিয়াকলাপ সম্পাদনের ক্রমটি আলাদা হতে পারে।

এবং সেইজন্য.

সঠিক উত্তরটি হ'ল এটি ব্যবহার করা উচিত নয়! (এটি নির্ধারিত হিসাবে!)

হ্যাঁ .. - সি # কমপ্লায়ার কোনওভাবে এটি স্বাভাবিক করার চেষ্টা করলেও এর অপ্রত্যাশিত ফলাফল রয়েছে।

আপনারা সকলেই ভাষার স্বাভাবিক বা সংজ্ঞায়িত আচরণ হিসাবে নথিভুক্ত আচরণের বর্ণনা দেওয়ার জন্য সি # এর কোনও নথিপত্র পাইনি। যা পেলাম ঠিক তার উল্টোটা!

[ পোস্টফিক্স বৃদ্ধি এবং হ্রাস অপারেটরদের জন্য এমএসডিএন ডকুমেন্টেশন থেকে অনুলিপি করা হয়েছে: ++ এবং - ]

কোনও পোস্টফিক্স অপারেটর যখন কোনও ফাংশন আর্গুমেন্টে প্রয়োগ করা হয়, তখন আর্গুমেন্টটির মানটি ফাংশনে পাস হওয়ার আগে বাড়ানো বা হ্রাস করার নিশ্চয়তা দেওয়া হয় না । আরও তথ্যের জন্য C ++ স্ট্যান্ডার্ডের বিভাগ 1.9.17 দেখুন।

এই শব্দগুলি গ্যারান্টিযুক্ত না লক্ষ্য করুন ...

যদি উত্তরটি অহংকারী মনে হয় তবে আমাকে ক্ষমা করুন - আমি অহঙ্কারী ব্যক্তি নই। আমি কেবল বিবেচনা করছি যে হাজার হাজার লোক এখানে শিখতে আসে এবং আমি যে উত্তরগুলি পড়ে তা তাদের বিভ্রান্ত করবে এবং তাদের যুক্তি এবং বিষয়টির বোঝার ক্ষতি করবে।


আমি নিশ্চিত না যে আমি 100% অনুসরণ করছি তবে আপনি সি ++ ডকুমেন্টেশন উল্লেখ করেছেন, তবে আমার প্রশ্নটি সি # সম্পর্কে ছিল। এখানে ডকুমেন্টেশন এখানে
পিটার

আমি আমার উত্তরে সি # তে উল্লেখ করছিলাম। আপনার সরবরাহিত লিঙ্কটি থেকে: x ++ বা x-- এর ফলাফলটি অপারেশনের আগে x এর মান, যেখানে ++ x বা --x এর ফলাফল অপারেশনের পরে x এর মান। উভয় ক্ষেত্রেই এক্স অপারেশনের পরে একই মান রয়েছে। পরিষ্কারভাবে দেখায় যে পরীক্ষার সময় এটি ঘটনা নয় .. কারণ এর i=++iথেকে বিভিন্ন ফলাফল সরবরাহ করা হবে i=i++। সুতরাং আমার উত্তর দাঁড়িয়ে।
জিওয়াই

আহা, ঠিক আছে, তবে আপনি সি ++ ডকুমেন্টেশনের উল্লেখ হিসাবে এটি বিভ্রান্তিকর। সুতরাং আপনি কী বলছেন যে স্পেসিফিকেশনটি সঠিকভাবে কার্যকর হয়নি?
পিটার

না, আমি যা বলছি তা হ'ল স্পেসিফিকেশন অনুসারে এটি অপরিজ্ঞাত, এবং অপরিজ্ঞাত ব্যবহার অনির্ধারিত ফলাফলের মধ্যেই শেষ হবে।
জিওয়াই

সি ++ এ অপরিজ্ঞাত, তবে সি # বলেছে যে অপারেশনের পরে এটি একই মান হওয়া উচিত , না? এটি অপরিবর্তিতের মতো নয় (তবে আমি আপনাকে সম্মত করি যে আপনি এটি ব্যবহার করবেন না, আমার দাবি অস্বীকার করুন, আমি কী চলছে তা বোঝার চেষ্টা করছি)।
পিটার

4

ভেরিয়েবলের পরে ++ অপারেটর এটি একটি পোস্টফিক্স ইনক্রিমেন্ট করে। বর্ধনের সমস্ত কিছু বিবৃতিতে যুক্তকরণ এবং কার্যভারের পরে ঘটে। পরিবর্তে, আপনি ভেরিয়েবলের আগে ++ রাখেন, আমার মানটি মূল্যায়নের আগে এটি ঘটবে এবং আপনাকে প্রত্যাশিত উত্তর দেবে।


2
++ঘটে না পরে+= বিবৃতি ঘটনাচক্রে সময় সঞ্চালনের +=বিবৃতি। এজন্যই এর প্রভাবগুলি ++ওভাররাইড করে +=
dtb

++ i ব্যবহারের ফলাফলটি আসলে 1-এ হয়, 2-তে নয় (আমার মূলত 'প্রত্যাশিত উত্তর')।
পিটার

দেখে মনে হচ্ছে অ্যাসাইনমেন্টটি এক্সপ্রেশনটিতে প্রাক-বা পোস্ট-ইনক্রিমেন্টের কারণে পরিবর্তনটি += ওভাররাইট করে।
স্টিভেন লু

4

গণনার পদক্ষেপগুলি হ'ল:

  1. int i=0 // 0 এ শুরু হয়েছে
  2. i+=i++ // সমীকরণ
  3. i=i+i++ // সংকলক দ্বারা সমীকরণ সহজ করার পরে
  4. i=0+i++ // আমি প্রতিস্থাপন মূল্য
  5. i=0+0 নীচে বর্ণিত হিসাবে // আই ++ 0 হয়
  6. i=0 // চূড়ান্ত ফলাফল আমি = 0

এখানে, প্রাথমিকভাবে মান i0 ডাব্লু কেটি, i++এটি ছাড়া আর কিছুই নয়: প্রথমে iমানটি ব্যবহার করুন এবং তারপরে iমানটি 1 দ্বারা বৃদ্ধি করুন । সুতরাং এটি iগণনা করার সময় 0 মানটি ব্যবহার করে i++এবং পরে এটি 1 দ্বারা বৃদ্ধি করে So 0 এর।


3

দুটি বিকল্প রয়েছে:

প্রথম বিকল্প: যদি সংকলক নীচের মত বিবৃতিটি পড়েন,

i++;
i+=i;

তারপরে ফলাফল 2।

জন্য

else if
i+=0;
i++;

ফলাফল 1।


5
যার কোনটিই আসল ফলাফল নয়।
স্টিভেন লু

3

খুব সতর্ক থাকুন: পড়া সি প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী : আপনি (assignement মিশ এবং চেষ্টা করছি কি ++একই ভেরিয়েবলের) না শুধুমাত্র অনির্দিষ্ট, কিন্তু এটি undefined করা হয় (যার অর্থ কম্পাইলার করতে পারে যে কিছু যখন মূল্যায়নের !, শুধুমাত্র দিচ্ছেন না "যুক্তিযুক্ত" ফলাফল)।

অনুগ্রহ করে পড়ুন, অধ্যায় 3 । পুরো বিভাগটি ভালভাবে পড়ার মতো! বিশেষত ৩.৯, যা অনির্ধারিতদের বোঝায়। বিভাগ 3.3 আপনাকে "i ++" এবং এর মতো আপনি কী করতে পারেন এবং কী করতে পারবেন না তার একটি দ্রুত সংক্ষিপ্তসার দেয়।

সংকলক ইন্টার্নালগুলির উপর নির্ভর করে আপনি 0, বা 2, বা 1, বা অন্য কিছু পেতে পারেন! এবং এটি অপরিজ্ঞাত হিসাবে, এটি করা তাদের পক্ষে ঠিক।


ওফস, সি # ... আমাকে "জিসিসি" দিয়ে ফেলে দেওয়া হয়েছিল কেউ কেউ কোড বিচ্ছিন্ন করতে গিয়েছিলেন।
অলিভিয়ার ডুলাক

1
আমি এটি সি # তেও মিস করেছি, তবে যাইহোক উত্তরটি পছন্দ করেছি।
আয়েন কলিন্স

1
@ আইইন: ধন্যবাদ, আমিও বিশ্বাস করি যে উত্তরটি উপলব্ধ রাখা ভাল ছিল, অনেক ব্যক্তি এই বিষয়ে (বা সেই মহান ফ্যাক্স সম্পর্কে) জানেন না , ইউজনেটের সেরা সময় থেকে যেখানে সাবজেক্টের জ্ঞানসম্পন্ন বেশিরভাগ লোক একই রকম চলেছিল এটি আপডেট করার জন্য স্থান)
অলিভিয়ার ডুলাক

3

উপরের উত্তরে চমৎকার যুক্তি রয়েছে, আমি কেবল একটি ছোট পরীক্ষা করেছি এবং আপনার সাথে ভাগ করে নিতে চাই

int i = 0;
i+ = i++;

এখানে ফলাফল আমি 0 ফলাফল দেখাচ্ছে। এখন নীচের মামলাগুলি বিবেচনা করুন:

মামলা 1:

i = i++ + i; //Answer 1

এর আগে আমি ভেবেছিলাম কোডটির সাথে উপরের মিল রয়েছে তাই প্রথম দেখায় উত্তরটি 1 হয়, এবং সত্যই এই উত্তরটির জন্য i এর উত্তর 1 হয়।

কেস 2:

i = i + i++; //Answer 0 this resembles the question code.

এখানে ইনক্রিমেন্ট অপারেটর মৃত্যুদন্ডের পথে আসে না, পূর্ববর্তী ক্ষেত্রে যেমন i++ যোগ করার আগে মৃত্যুদন্ড কার্যকর করার সুযোগ পায় unlike

আমি আশা করি এটি কিছুটা সাহায্য করবে। ধন্যবাদ


2

সি প্রোগ্রামিংয়ের 101 প্রকারের দৃষ্টিকোণ থেকে এটির উত্তর দেওয়ার প্রত্যাশা।

আমার কাছে দেখে মনে হচ্ছে এটি এই ক্রমে ঘটছে:

  1. i0 হিসাবে মূল্যায়ন করা হয়, ফলস্বরূপ i = 0 + 0ইনক্রিমেন্ট অপারেশন i++"সারি" করা হয়, তবে 0 এর অ্যাসাইনমেন্টটি iএখনও হয় নি।
  2. বর্ধন i++ঘটে
  3. i = 0উপরের দিক থেকে অ্যাসাইনমেন্টটি ঘটেছে, কার্যকরভাবে # 2 (পোস্ট-ইনক্রিমেন্ট) যা কিছু করেছে তা ওভাররাইট করে।

এখন, # 2 আসলে কখনই ঘটে না (সম্ভবত হয় না?) কারণ সংকলক সম্ভবত বুঝতে পারে যে এটি কোনও উদ্দেশ্য করে না, তবে এটি সংকলক নির্ভর হতে পারে। যেভাবেই হোক না কেন, আরও জ্ঞানসম্মত উত্তরগুলি দেখিয়েছে যে ফলাফলটি সঠিক এবং সি # স্ট্যান্ডার্ডের সাথে খাপ খায় তবে এটি সি / সি ++ এর জন্য কী ঘটে তা সংজ্ঞায়িত করা হয়নি।

কীভাবে এবং কেন আমার দক্ষতার বাইরে, তবে পূর্বের মূল্যায়ন ডান-হাতের অ্যাসাইনমেন্ট পোস্ট-ইনক্রিমেন্টের পরে ঘটে যা সম্ভবত এখানে বিভ্রান্তিকর।

উপরন্তু, আপনি যদি না তুমি করেছ ফলাফলের নির্বিশেষে 2 বলে আশা করা যাবে না ++iপরিবর্তে i++আমি বিশ্বাস করি।


1
প্রিনক্রেনমেন্ট সংস্করণটি 2সি ++ এর সাথে ফলাফল তৈরি করে : আদর্শ one.com/8dH8tf
স্টিভেন লু

এটা বোধগম্য. তবে প্রাক-বর্ধন পরবর্তী পোস্টের তুলনায় সামান্য কম জটিল পরিস্থিতি।
gkimsey

2

সহজভাবে করা,

i ++, "+" "অপারেটরটি শেষ হওয়ার পরে 1" i "তে যুক্ত হবে।

আপনি যা চান তা ++ i, যাতে এটি "+" "অপারেটর কার্যকর হওয়ার আগে এটি" i "তে 1 যুক্ত করে।


0
i=0

i+=i

i=i+1

i=0;

তারপরে 1 টি যুক্ত করা হয় i

আমি + = আমি ++,

1 এ যোগ করার আগে 0 এর মান নিয়েছিল i, iকেবলমাত্র আমরা আগে 1 যুক্ত iকরলে মান 0 পান।

i+=++i

i=2

-4

উত্তর iহবে 1

আসুন দেখে নেওয়া যাক কীভাবে:

প্রাথমিকভাবে i=0;

তারপরে i +=i++;মান অনুসারে গণনা করার সময় আমাদের মতো কিছু থাকবে 0 +=0++;, সুতরাং অপারেটর অগ্রাধিকার অনুযায়ী 0+=0প্রথমে সম্পাদন করবে এবং ফলাফল হবে 0

তারপর বৃদ্ধি অপারেটর হিসেবে প্রয়োগ হবে 0++, যেমন 0+1এবং এর মান iহতে হবে 1


3
এই উত্তরটি ভুল। আপনি 1 পাবেন না কারণ আপনি যখন 0 += 0++;অ্যাসাইনমেন্ট করেন তখন ইনক্রিমেন্টের পরে হয় ++তবে আমার মানটির আগে ব্যাখ্যা করা হয় ++(কারণ একটি পোস্ট অপারেটর
ফোনিক্স

2
দুঃখিত, তবে এটি ভুল। আমার প্রশ্নটি পড়ুন এবং আপনি দেখতে পাবেন যে আমি ফলাফলটি 0 পেয়েছি আপনি যদি কোডটি চালনা করেন তবে আপনি এটি কার্যকরভাবে দেখতে পাবেন 0
পিটার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.