কেন এটি অসীম লুপে যায়?


493

আমার কাছে নিম্নলিখিত কোড রয়েছে:

public class Tests {
    public static void main(String[] args) throws Exception {
        int x = 0;
        while(x<3) {
            x = x++;
            System.out.println(x);
        }
    }
}

আমরা জানি যে তার লিখিত হওয়া উচিত ছিল কেবল x++বা x=x+1, তবে এর উপর x = x++প্রথমে xনিজের কাছে গুণিত হওয়া উচিত , এবং পরে এটি বৃদ্ধি করা উচিত। মান হিসাবে কেন xচালিয়ে যায় 0?

--হালনাগাদ

এখানে বাইকোড:

public class Tests extends java.lang.Object{
public Tests();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_3
   4:   if_icmpge   22
   7:   iload_1
   8:   iinc    1, 1
   11:  istore_1
   12:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   15:  iload_1
   16:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   19:  goto    2
   22:  return

}

আমি বুঝতে চেষ্টা করার নির্দেশাবলী সম্পর্কে পড়তে হবে ...


8
আমার সন্দেহ হচ্ছে যা হচ্ছে তা হল: 1. একটি রেজিস্টারে এক্স লোড করুন (= 0); 2. ইনক্রিমেন্ট এক্স (x = 1); ৩. রেজিস্ট্রার মান সংরক্ষণ করুন (x = 0)। সি / সি ++ এ এটি অপরিজ্ঞাত আচরণ হবে কারণ 2 এবং 3 এর ক্রম সংজ্ঞায়িত করার জন্য কোনও আনুষ্ঠানিক অনুক্রম বিন্দু নেই আশা করি কেউ আপনাকে জাভা স্পেস থেকে সমমানের কিছু উদ্ধৃত করতে পারে।
রুপ

19
আমরা কী হবে তা দেখতে সি ++ এ চেষ্টা করেছিলাম এবং এটি 1,2,3 মুদ্রণ করে প্রস্থান করে। আমি না আশা। আমি অনুমান করি এটি সংকলক নির্ভরশীল, যেহেতু এটি নির্ধারিত আচরণ। আমরা gnu ++ ব্যবহার করেছি।
শোক করুন

13
@ সজ x++পোস্ট-ইনক্রিমেন্ট; ফলাফলেরx= অ্যাসাইনমেন্ট ; ফলাফলের এর আসল (এবং সেখানে বৃদ্ধি একটি পার্শ্ব-প্রতিক্রিয়া, কিন্তু যে ফলাফলের পরিবর্তন করে না), তাই এই হিসাবে ব্যাখ্যা করা যেতে পারেx++xvar tmp = x; x++; x = tmp;
মার্ক Gravell

5
এখন আমার কাছে একটি জনপ্রিয় প্রশ্ন রয়েছে যেটির জন্য আমি আফসোস করছি, সঠিক উত্তরটি নির্বাচিত হওয়ার পরেও (পুনরাবৃত্ত) উত্তরগুলি আসা বন্ধ হবে না। আমার "সাম্প্রতিক ক্রিয়াকলাপ" স্ক্রিনটি একই উত্তরগুলির সাথে পূর্ণ, এবং আরও আসছে ...
টম ব্রিটো

3
@ রব ভার্মুলেন আপনি মন্তব্য করার আগে পুরো প্রশ্নটি পড়তে চাইতে পারেন ..;) এটি আমার একজন শিক্ষার্থীর তৈরি কোড ছিল এবং আমি কেন এই আচরণের কারণে আগ্রহী ছিলাম।
টম ব্রিটো

উত্তর:


354

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


সম্ভবত আমরা যদি কোনও পদ্ধতি লিখে রাখি যা x++এটি কী করে তার সমতুল্য করার জন্য এটি আরও পরিষ্কার করে দেবে।

public MutableInt postIncrement(MutableInt x) {
    int valueBeforeIncrement = x.intValue();
    x.add(1);
    return new MutableInt(valueBeforeIncrement);
}

রাইট? উত্তীর্ণ হওয়া মান বৃদ্ধি করুন এবং আসল মানটি ফিরিয়ে দিন: এটি পোস্ট-সংশ্লেষ অপারেটরের সংজ্ঞা।

এখন, আসুন দেখুন আপনার উদাহরণ কোডে এই আচরণটি কীভাবে কার্যকর হয়:

MutableInt x = new MutableInt();
x = postIncrement(x);

postIncrement(x)কি করে? xহ্যাঁ, বৃদ্ধি । এবং তারপরে ইনক্রিমেন্টের আগে যা x ছিল তা ফিরিয়ে দেয় । এই রিটার্ন মানটি তখন নির্ধারিত হয় x

সুতরাং নির্ধারিত মানগুলির ক্রম x0, তারপরে 1, তার পরে 0 হবে।

আমরা উপরেরটি আবার লিখলে এটি আরও স্পষ্ট হতে পারে:

MutableInt x = new MutableInt();    // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp;                           // Now x is 0 again.

xউপরের অ্যাসাইনমেন্টটির বাম দিকে আপনি যখন প্রতিস্থাপন করেন তখন এই বিষয়ে আপনার স্থিরতা y"আপনি দেখতে পাচ্ছেন যে এটি প্রথমে এক্স বৃদ্ধি করে এবং পরে এটি y এর সাথে যুক্ত করে" আমাকে বিভ্রান্ত করে তোলে। এটি xযে বরাদ্দ করা হচ্ছে তা নয় y; এটি পূর্বে নির্ধারিত মানx । সত্যই, ইনজেকশন yজিনিসকে উপরের পরিস্থিতি থেকে আলাদা করে তোলে না; আমরা কেবল পেয়েছি:

MutableInt x = new MutableInt();    // x is 0.
MutableInt y = new MutableInt();    // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp;                           // y is still 0.

সুতরাং এটি পরিষ্কার: x = x++কার্যকরভাবে এক্স এর মান পরিবর্তন করে না। এটি সর্বদা x এর মান x 0 , তারপরে x 0 + 1 এবং তারপরে আবার x 0 করে।


আপডেট : ঘটনাচক্রে, সম্ভবত আপনি সন্দেহ করবেন না যে xউপরোক্ত উদাহরণে বর্ধিত ক্রিয়াকলাপ এবং অ্যাসাইনমেন্টের মধ্যে কখনই "1" অর্পণ করা হয়েছে, আমি একটি দ্রুত ডেমো একসাথে নিক্ষেপ করেছি যে এই মধ্যবর্তী মানটি প্রকৃতপক্ষে "বিদ্যমান" আছে যদিও এটি হবে এক্সিকিউটিভ থ্রেডে কখনই "দেখা" হবে না।

ডেমো x = x++;একটি লুপে কল করে যখন একটি পৃথক থ্রেড ক্রমাগত xকনসোলের মান প্রিন্ট করে ।

public class Main {
    public static volatile int x = 0;

    public static void main(String[] args) {
        LoopingThread t = new LoopingThread();
        System.out.println("Starting background thread...");
        t.start();

        while (true) {
            x = x++;
        }
    }
}

class LoopingThread extends Thread {
    public @Override void run() {
        while (true) {
            System.out.println(Main.x);
        }
    }
}

নীচে উপরের প্রোগ্রামটির আউটপুট এর একটি অংশ রয়েছে। 1 এবং 0 উভয় ক্ষেত্রেই অনিয়মিত ঘটনা লক্ষ্য করুন।

পটভূমি থ্রেড শুরু হচ্ছে ...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1

1
জাভাতে রেফারেন্স দিয়ে পাস করার জন্য আপনার কোনও ক্লাস তৈরি করার দরকার নেই (যদিও এটি অবশ্যই কাজ করবে)। আপনি Integerক্লাসটি ব্যবহার করতে পারেন , এটি স্ট্যান্ডার্ড লাইব্রেরির অংশ এবং এটি int প্রায় স্বচ্ছভাবে স্বয়ংক্রিয়ভাবে বাক্সযুক্ত হওয়ার সুবিধাও রয়েছে ।
rmeador

3
@ রোমাদোর পূর্ণসংখ্যা অপরিবর্তনীয়, তাই আপনি এখনও এর মান পরিবর্তন করতে পারেন নি। অ্যাটমিকআইন্টিজার অবশ্য পরিবর্তনীয়।
ILMTitan

5
@ ড্যান: যাইহোক, xআপনার শেষ উদাহরণটি অবশ্যই ঘোষণা করতে হবে volatile, অন্যথায় এটি একটি সংজ্ঞায়িত আচরণ এবং 1এর লক্ষ্য বাস্তবায়ন নির্দিষ্ট।
axtavt

4
@ বারকেষ্টার: আমি মনে করি না যে এই ক্ষেত্রে লিঙ্কটি বেশ উপযুক্ত, কারণ এটি একটি জাভা প্রশ্ন এবং (যদি আমি ভুল না করি) আচরণটি আসলে C ++ এ অপরিজ্ঞাত।
ড্যান তাও

5
@ টম ব্রিটো - সি তে এটি সংজ্ঞায়িত করা হয়নি ... কার্যভারের আগে বা পরে করা ++ যেতে পারে। ব্যবহারিকভাবে বলতে গেলে, এমন একটি সংকলক হতে পারে যা জাভা হিসাবে একই কাজ করে তবে আপনি এটিতে বাজি ধরতে চান না।
স্পষ্টভাবে

170

x = x++ নিম্নলিখিত পদ্ধতিতে কাজ করে:

  • প্রথমে এটি প্রকাশের মূল্যায়ন করে x++। এই মত প্রকাশের মূল্যায়ন একটি অভিব্যক্তি মান (যার মান উৎপন্ন xএবং বাড়তি সামনে বৃদ্ধি) x
  • পরে এটি xবর্ধিত মান ওভাররাইট করে এক্সপ্রেশন মানকে নির্ধারিত করে ।

সুতরাং, ইভেন্টগুলির ক্রমটি নীচের মতো দেখাচ্ছে (এটি javap -cআমার মন্তব্য সহ উত্পাদিত হিসাবে সত্যিকারের ক্ষয়প্রাপ্ত বাইকোড ):

   8: ইলোয়াড_1 // স্ট্যাকের এক্স এর বর্তমান মান মনে রাখবেন
   9: প্রথম 1, 1 // বৃদ্ধি এক্স (স্ট্যাক পরিবর্তন করে না)
   12: istore_1 // স্ট্যাক থেকে এক্স পর্যন্ত রেকর্ডিং মান লিখুন

তুলনার জন্য x = ++x,:

   8: আইক 1, 1 // বৃদ্ধি এক্স
   11: আইলোড_1 // স্ট্যাকের উপর এক্স এর মান ধাক্কা
   12: istore_1 // স্ট্যাক থেকে এক্স এ পপ মান

যদি আপনি একটি পরীক্ষা করেন তবে আপনি দেখতে পাবেন যে এটি প্রথমে বৃদ্ধি হয় এবং পরে বৈশিষ্ট্যগুলি। সুতরাং এটি শূন্য বৈশিষ্ট্যযুক্ত করা উচিত নয়।
টম ব্রিটো

2
@ টম এটাই মূল বিষয় যদিও - কারণ এটি সমস্ত একক ক্রম হ'ল এটি একটি অ-সুস্পষ্ট (এবং সম্ভবত অপরিবর্তিত) ক্রমে কাজ করছে। এটি পরীক্ষা করার চেষ্টা করে আপনি একটি সিকোয়েন্স পয়েন্ট যুক্ত করছেন এবং বিভিন্ন আচরণ পেয়ে যাচ্ছেন।
রুপ

আপনার বাইটকোড আউটপুট সম্পর্কে: নোট করুন যে iincএকটি পরিবর্তনশীল বৃদ্ধি করে, এটি কোনও স্ট্যাকের মান বাড়ায় না, বা এটি স্ট্যাকের উপর কোনও মান রাখে না (প্রায় প্রতিটি গাণিতিক অপটির মতো নয়)। আপনি ++xতুলনা করার জন্য উত্পন্ন কোড যুক্ত করতে চাইবেন ।
আনন

3
@ রেপ এটি সি বা সি ++ এ সংজ্ঞায়িত করা হতে পারে না তবে জাভাতে এটি ভালভাবে সংজ্ঞায়িত হয়েছে।
ILMTitan


104

এটি ঘটে কারণ এর মান xএকেবারেই বৃদ্ধি পায় না।

x = x++;

সমতুল্য

int temp = x;
x++;
x = temp;

ব্যাখ্যা:

আসুন এই অপারেশনের জন্য বাইট কোডটি দেখুন। একটি নমুনা শ্রেণি বিবেচনা করুন:

class test {
    public static void main(String[] args) {
        int i=0;
        i=i++;
    }
}

এখন আমরা ক্লাস বিচ্ছিন্ন করার যন্ত্রটি চালিয়ে যাচ্ছি:

$ javap -c test
Compiled from "test.java"
class test extends java.lang.Object{
test();
  Code:
   0:    aload_0
   1:    invokespecial    #1; //Method java/lang/Object."<init>":()V
   4:    return

public static void main(java.lang.String[]);
  Code:
   0:    iconst_0
   1:    istore_1
   2:    iload_1
   3:    iinc    1, 1
   6:    istore_1
   7:    return
}

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

আমাদের দিকে দেখি স্মৃতিবর্ধনবিদ্যা মধ্যে main()পদ্ধতি:

  • iconst_0: ধ্রুবক মানটি 0 স্ট্যাকের দিকে এগিয়ে যায়।
  • istore_1: স্ট্যাকের শীর্ষ উপাদানটি পপ আউট এবং সূচক সহ স্থানীয় ভেরিয়েবলে সংরক্ষণ করা হয় 1
    যা সংরক্ষণ করা হয় x
  • iload_1 : অবস্থান মান 1 মান x যেটির মান 0এটি স্ট্যাকের মধ্যে চাপ দেওয়া হয়।
  • iinc 1, 1: মেমরি অবস্থানের মান 1দ্বারা বাড়ানো হয়1 । তাই xএখন হয়ে যায় 1
  • istore_1: স্ট্যাকের শীর্ষে থাকা মানটি মেমরির জায়গায় সংরক্ষণ করা হয় 1। অর্থাৎ 0নির্ধারিত হয়x মুছে যাওয়ার তার বৃদ্ধি মান।

অতএব xঅসীম লুপের ফলে মানটির কোনও পরিবর্তন হয় না।


5
আসলে এটি বর্ধিত হয় (এর অর্থ thats ++), তবে ভেরিয়েবলটি ওভাররাইট হয়ে যায় পরে।
প্রোগ্রামম্যান

10
int temp = x; x = x + 1; x = temp;আপনার উদাহরণে টাউটোলজি ব্যবহার না করা ভাল।
স্কট চেম্বারলাইন

52
  1. প্রিফিক্স স্বরলিপিটি এক্সপ্রেশনটি মূল্যায়ন করার আগে পরিবর্তনশীলকে বৃদ্ধি করবে।
  2. পোস্টফিক্স স্বরলিখনটি এক্সপ্রেশন মূল্যায়নের পরে বৃদ্ধি পাবে।

তবে " =" এর তুলনায় " ++" অপারেটরটি কম রয়েছে ।

সুতরাং x=x++;নিম্নলিখিত হিসাবে মূল্যায়ন করা উচিত

  1. x নিয়োগের জন্য প্রস্তুত (মূল্যায়ন)
  2. x বৃদ্ধি
  3. xনির্ধারিত পূর্বের মান x

এটি সেরা উত্তর। কিছু মার্কআপ এটিকে আরও কিছুটা দাঁড়াতে সহায়তা করবে।
জাস্টিন ফোর্স

1
এটা ভুল. এটি নজির নয়। সি এবং সি ++ এর ++চেয়ে বেশি প্রাধান্য রয়েছে =তবে বিবৃতিটি সেই ভাষাগুলিতে অপরিজ্ঞাত।
ম্যাথু ফ্ল্যাশেন

2
আসল প্রশ্নটি জাভা সম্পর্কে
জয়দি

34

বেশিরভাগ উত্তর যেখানে নেই সেখানে এখানে যায়:

আপনি যখন লিখছেন int x = x++, আপনি xনতুন মান হিসাবে নিজেকে হস্তান্তর করছেন না , আপনি এক্সপ্রেশনটির xরিটার্ন মান হিসাবে নির্ধারিত করছেন x++কোলিন কোচরেনের উত্তরেx ইঙ্গিত হিসাবে এটির মূল মূল্য হিসাবে দেখা যায় ।

মজাদার জন্য, নিম্নলিখিত কোডটি পরীক্ষা করুন:

public class Autoincrement {
        public static void main(String[] args) {
                int x = 0;
                System.out.println(x++);
                System.out.println(x);
        }
}

ফলাফল হবে

0
1

এক্সপ্রেশনটির রিটার্ন মান হ'ল প্রাথমিক মান x, যা শূন্য। তবে পরে, এর মান পড়ার সময় xআমরা আপডেট হওয়া মানটি পাই, এটি একটি।


আমি বাইটকোড লাইনগুলি বোঝার চেষ্টা করব, আমার আপডেটটি দেখুন, তাই এটি পরিষ্কার হয়ে যাবে .. :)
টম ব্রিটো

এটি বোঝার জন্য প্রিন্টলন () ব্যবহার করা আমার পক্ষে খুব সহায়ক ছিল।
এরিক

29

এটি ইতিমধ্যে অন্য দ্বারা ভাল ব্যাখ্যা করা হয়েছে। আমি কেবল প্রাসঙ্গিক জাভা স্পেসিফিকেশন বিভাগগুলির লিঙ্কগুলি অন্তর্ভুক্ত করছি।

x = x ++ একটি প্রকাশ। জাভা মূল্যায়ন আদেশ অনুসরণ করবে । এটি প্রথমে এক্স ++ এক্সপ্রেশনটি মূল্যায়ন করবে, যা এক্স বৃদ্ধি করবে এবং এক্স এর আগের মানকে ফলাফলের মান নির্ধারণ করবে । এরপরে এটি এক্সপ্রেশন ফলাফলটি ভেরিয়েবল এক্স-এর জন্য বরাদ্দ করবে । শেষে, x এর আগের মানটিতে ফিরে এসেছে।


1
+1 টি। এটি প্রকৃত প্রশ্নের সর্বোত্তম উত্তর, "কেন?"
ম্যাথু ফ্ল্যাশেন

18

এই বিবৃতি:

x = x++;

এই মত মূল্যায়ন:

  1. ধাক্কা xস্ট্যাকের উপর ;
  2. বৃদ্ধি x;
  3. xস্ট্যাক থেকে পপ করুন ।

সুতরাং মানটি অপরিবর্তিত। এর সাথে তুলনা করুন:

x = ++x;

যা মূল্যায়ন করে:

  1. বৃদ্ধি x;
  2. xস্ট্যাকের উপর ধাক্কা ;
  3. xস্ট্যাক থেকে পপ করুন ।

আপনি যা চান তা হ'ল:

while (x < 3) {
  x++;
  System.out.println(x);
}

13
অবশ্যই সঠিক বাস্তবায়ন, তবে প্রশ্নটি 'কেন?'।
পি.কম্পবেল

1
মূল কোডটি এক্স-তে পোস্ট-ইনক্রিমেন্ট ব্যবহার করছিল এবং তারপরে এটি এক্সকে নির্ধারণ করছিল। এক্স ইনক্রিমেন্টের আগে x এর সাথে আবদ্ধ হবে, সুতরাং এটি কখনই মান পরিবর্তন করে না।
wkl

5
@ ক্লেটাস আমি ডাউনভোটার নই, তবে আপনার প্রাথমিক উত্তরটিতে ব্যাখ্যাটি নেই। এটি কেবল 'x ++ `করতে বলেছে`
পেটার মিনচেভ

4
@ ক্লেটাস: আমি নীচে নামিনি, তবে আপনার উত্তরটি ছিল কেবল x++কোড স্নিপেট।
পি.কম্পবেল

10
ব্যাখ্যাটিও ভুল। কোডটি যদি প্রথমে x এ x নির্ধারিত হয় এবং তারপরে এক্স ইনক্রিমেন্টেড থাকে তবে এটি ঠিকঠাক কাজ করবে। কেবল x++;আপনার সমাধানটিতে পরিবর্তন করুন x=x; x++;এবং আপনি যা করছেন দাবি করছেন যে আসল কোডটি করছে।
উবুল

10

উত্তরটি বেশ সোজা is ক্রম জিনিস মূল্যায়ন করা হয় এর সাথে এটি করতে হয়। x++মান প্রদান করে xইনক্রিমেন্টগুলি x

ফলস্বরূপ, অভিব্যক্তির মান x++হয় 0। সুতরাং আপনি x=0লুপ প্রতিটি সময় বরাদ্দ করা হয়। অবশ্যই x++এই মানটি বাড়ায় তবে অ্যাসাইনমেন্টের আগে এটি ঘটে।


1
বাহ, উত্তরটি সংক্ষিপ্ত এবং সহজ অর্থাত্‍ এইটি যখন এই পৃষ্ঠায় এতগুলি বিশদ রয়েছে।
চার্লস গুডউইন

8

Http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html থেকে

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

উদাহরণস্বরূপ, নিম্নলিখিত চেষ্টা করুন:

    int x = 0;
    int y = 0;
    y = x++;
    System.out.println(x);
    System.out.println(y);

যা 1 এবং 0 মুদ্রণ করবে।


1
এটি মূল্যায়নের ফলাফল নয় এটিই সমস্যা, যদিও এটি স্টোরগুলির ক্রম।
রুপ

2
আমি একমত নই তাহলে এক্স = 0 তারপর এক্স ++, 0. ফিরে আসবে তাই এক্স = এক্স ++, এক্স = 0. হবে
কলিন মধ্যে Cochrane

রুপ এই সম্পর্কে সঠিক। এই বিশেষ ক্ষেত্রে এটি বিতর্কিত দোকানগুলির ক্রম। y = x ++ x = x ++ এর মতো নয়; একের পরে, এক্সকে একই এক্সপ্রেশনটিতে 2 টি মান নির্ধারণ করা হচ্ছে। বাম হাত এক্স এক্সপ্রেশন এক্স ++ এর মূল্যায়নের ফলাফল নির্ধারণ করা হচ্ছে , যা 0 হয়। ডান হাতের সাইড এক্সটি 1 বাড়ানো হচ্ছে। এই 2 কার্যনির্বাহী ক্রমটি ক্রমের ক্ষেত্রে কী ঘটে তা হল। পূর্ববর্তী পোস্টগুলি থেকে এটি পরিষ্কার হয় যে এটি কীভাবে কাজ করে তা হল: eval = x ++ => eval == 0: বর্ধিত ডান x => x == 1: বাম x = ইভাল => এক্স == 0
মাইকেল একোকা

7

আপনি কার্যকরভাবে নিম্নলিখিত আচরণ পাচ্ছেন।

  1. ডান পাশের "ফলাফল" হিসাবে x এর মান (যা 0 হয়) ধরুন
  2. এক্স এর মান বৃদ্ধি (সুতরাং এক্স এখন 1)
  3. ডান পাশের ফলাফলকে (যা 0 হিসাবে সংরক্ষণ করা হয়েছিল) এক্স-তে নির্ধারণ করুন (এক্স এখন 0)

ধারণাটি হ'ল যে পোস্ট-ইনক্রিমেন্ট অপারেটর (x ++) বর্ধিত হয় যা প্রশ্নে পরিবর্তনশীল হয় তার ব্যবহৃত সমীকরণটি ব্যবহারের জন্য তার মান ফেরত দেওয়ার পরে।

সম্পাদনা করুন: মন্তব্যটির কারণে কিছুটা যুক্ত করা হচ্ছে। এটি নীচের মত বিবেচনা করুন।

x = 1;        // x == 1
x = x++ * 5;
              // First, the right hand side of the equation is evaluated.
  ==>  x = 1 * 5;    
              // x == 2 at this point, as it "gave" the equation its value of 1
              // and then gets incremented by 1 to 2.
  ==>  x = 5;
              // And then that RightHandSide value is assigned to 
              // the LeftHandSide variable, leaving x with the value of 5.

ঠিক আছে, তবে কী পদক্ষেপ 2 এবং 3 এর ক্রম নির্দিষ্ট করে?
রূপ

@ রুপ - ভাষা এটি সংজ্ঞায়িত করে। সমীকরণের ডান দিকটি প্রথমে মূল্যায়ন করা হয় (এই ক্ষেত্রে, "x ++"), এবং ফলাফলটি বাম পাশের ভেরিয়েবলকে বরাদ্দ করা হয়। ভাষা এভাবেই কাজ করে। সমীকরণের জন্য যতদূর "x ++" "রিটার্নিং" এক্স, পোস্টফিক্স ইনক্রিমেন্ট অপারেটর কীভাবে কাজ করে (এক্স এর মান ফিরিয়ে দেয়, তারপরে এটি বৃদ্ধি করবে)। যদি এটি "--x" হত, তবে এটি হত (ইনক্রিমেন্ট এক্স, তারপরে মানটি ফিরিয়ে দিন)। ফিরতি এখানে সঠিক শব্দ নয়, তবে আপনি ধারণা পাবেন।
RHSeeger

7

কী ঘটছে তা বোঝার জন্য আপনার আসলে মেশিন কোডের দরকার নেই।

সংজ্ঞা অনুযায়ী:

  1. অ্যাসাইনমেন্ট অপারেটর ডান হাতের অভিব্যক্তিটি মূল্যায়ন করে এবং এটি একটি অস্থায়ী ভেরিয়েবলে সঞ্চয় করে।

    1.1। এক্স এর বর্তমান মানটি এই অস্থায়ী ভেরিয়েবলে অনুলিপি করা হয়

    1.2। এক্স এখন বৃদ্ধি করা হয়।

  2. অস্থায়ী পরিবর্তনশীলটি তখন এক্সপ্রেশনটির বাম দিকে অনুলিপি করা হয়, যা সুযোগের সাথে x! তাই X এর পুরানো মানটি আবার নিজের মধ্যে অনুলিপি করা হয়।

এটা বেশ সহজ।


5

এর কারণ এটি কখনও এই ক্ষেত্রে বর্ধিত হয় না। x++এই ক্ষেত্রে এর মতো বাড়ানোর আগে প্রথমে এর মানটি ব্যবহার করা হবে এটি এর মতো হবে:

x = 0;

তবে এটি করলে ++x;তা বাড়বে।


যদি আপনি একটি পরীক্ষা করেন তবে আপনি দেখতে পাবেন যে এটি প্রথমে বৃদ্ধি হয় এবং পরে বৈশিষ্ট্যগুলি। সুতরাং এটি শূন্য বৈশিষ্ট্যযুক্ত করা উচিত নয়।
টম ব্রিটো

1
@ টম: আমার উত্তরটি দেখুন - আমি একটি পরীক্ষায় দেখি যে এক্স ++ আসলে x এর পুরানো মানটি দেয়। সেখানেই এটি ভেঙে যায়।
রবার্ট মুন্তানু

"যদি আপনি একটি পরীক্ষা করেন" - কিছু লোক মনে হয় যে সি তে লিখিত একটি পরীক্ষা জাভা কী করবে তা আমাদের জানায়, যখন এটি সি কী করবে তা আমাদের জানায় না।
জিম বাল্টার

3

মান 0 থাকে কারণ 0 এর মান x++হয় 0 এই ক্ষেত্রে ভ্যালুটি xবাড়ানো বা না করা যায় না, কাজটি x=0নির্বাহ করা হয়। এটি অস্থায়ী বর্ধিত মানটির ওভাররাইট করবে x(যা "খুব স্বল্প সময়ের জন্য 1 ছিল)"।


তবে এক্স ++ একটি পোস্ট অপারেশন। সুতরাং অ্যাসাইনমেন্টটি শেষ হওয়ার পরে এক্স বাড়ানো হবে।
সাগর ভি

1
@ সাগর ভি: কেবল প্রকাশের x++জন্য, পুরো কার্যভারের জন্য নয়x=x++;
প্রোগ্রামম্যান

না, আমার মনে হয় অ্যাসাইনমেন্টটিতে এক্সের মানটি পড়ার পরে এটি কেবল বাড়ানো দরকার।
রূপান্তর

1

আপনি কীভাবে অন্যটির কাছে প্রত্যাশা করবেন এটি এটি কাজ করে। এটি উপসর্গ এবং পোস্টফিক্সের মধ্যে পার্থক্য।

int x = 0; 
while (x < 3)    x = (++x);

1

এক্স ++ কে একটি ফাংশন কল হিসাবে ভাবুন যা এক্স এর আগে যা ছিল "ফিরিয়ে দেয়" (এ কারণেই এটি পোস্ট-ইনক্রিমেন্ট বলা হয়)।

সুতরাং অপারেশন অর্ডারটি হ'ল:
1: এক্সক্রিমেন্টের আগে x এর মান ক্যাশে করুন
2: ইনক্রিমেন্ট এক্স
3: ক্যাশেড মানটি ফেরত দিন (এক্স বাড়ানোর আগে এক্স)
4: রিটার্ন মান এক্সকে নির্ধারিত করা হয়েছে


ঠিক আছে, তবে 3 এবং 4 পদক্ষেপের ক্রমটি কী নির্দিষ্ট করে?
রূপান্তর

"ইনক্রিমেন্টের আগে এক্স কী ছিল তা ফিরিয়ে দেয়", আমার আপডেট দেখুন
টম ব্রিটো

বাস্তবে 3 এবং 4 পদক্ষেপগুলি পৃথক ক্রিয়াকলাপ নয় - এটি আসলে কোনও ফাংশন কল নয় যা কোনও মান দেয়, এটি কেবল সেভাবে ভাবতে সহায়তা করে। যখনই আপনার একটি অ্যাসাইনমেন্ট রয়েছে ডান হাতের দিকটি "মূল্যায়ন" করা হয় তবে ফলাফলটি বাম হাতের কাছে বরাদ্দ করা হয়, মূল্যায়নের ফলাফলটি রিটার্নের মান হিসাবে বিবেচনা করা যেতে পারে কারণ এটি আপনাকে ক্রিয়াকলাপের ক্রম বুঝতে সহায়তা করে, তবে এটি সত্যই নয় not ।
jhabbott

উফ, সত্য। আমার অর্থ পদক্ষেপ 2 এবং 4 - কেন প্রত্যাশিত মানটি বর্ধিত মানের শীর্ষের উপরে সঞ্চিত হয়?
রূপ

1
এটি একটি অ্যাসাইনমেন্ট অপারেশনের সংজ্ঞাটির অংশ, প্রথমে ডান হাতটি সম্পূর্ণ মূল্যায়ন করা হয়, তারপরে ফলাফলটি বাম হাতের কাছে নির্ধারিত হয়।
habাববট

1

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


1

যতদূর আমি দেখতে পাচ্ছি, ত্রুটি ঘটে, বর্ধিত মানকে ওভাররাইড করার কারণে, বর্ধিতকরণের পূর্বে মান সহ, কারণ এটি বর্ধনকে পূর্বাবস্থায় ফেলে।

বিশেষত, "x ++" এক্সপ্রেশনটিতে "++ x" এর বিপরীতে বর্ধনের পূর্বে 'x' এর মান রয়েছে যার বর্ধিতকরণের পরে 'x' এর মান রয়েছে।

আপনি যদি বাইটকোডটি তদন্ত করতে আগ্রহী হন তবে আমরা প্রশ্নে তিনটি লাইন একবার দেখে নেব:

 7:   iload_1
 8:   iinc    1, 1
11:  istore_1

:: ইলোয়াড_1 # ২ য় স্থানীয় ভেরিয়েবলের মান স্ট্যাকের উপরে রাখবে
8: যেমন 1,1 # 2 এর সাথে দ্বিতীয় স্থানীয় ভেরিয়েবলকে বাড়িয়ে দেবে, দ্রষ্টব্য যে এটি স্ট্যাকটি আউটচুড রেখে গেছে!
9: istore_1 # স্ট্যাকের শীর্ষটি পপ করবে এবং এই উপাদানটির মান 2 য় স্থানীয় ভেরিয়েবলে সংরক্ষণ করবে
(আপনি এখানে প্রতিটি জেভিএম নির্দেশের প্রভাবগুলি পড়তে পারেন )

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

iinc 1,1
iload_1
istore_1

সুতরাং কেবলমাত্র দুটি প্রথম লাইন অদলবদল করে শব্দার্থবিজ্ঞানের পরিবর্তন ঘটায় যাতে বর্ধনের পরে (অর্থাত্ অভিব্যক্তির 'মান') বর্ধনের পরে মানটি স্ট্যাকের শীর্ষে রেখে যায়।


1
    x++
=: (x = x + 1) - 1

তাই:

   x = x++;
=> x = ((x = x + 1) - 1)
=> x = ((x + 1) - 1)
=> x = x; // Doesn't modify x!

যেহেতু

   ++x
=: x = x + 1

তাই:

   x = ++x;
=> x = (x = x + 1)
=> x = x + 1; // Increments x

অবশ্যই শেষ ফলাফলটি কেবল x++;বা ++x;নিজেই একটি লাইনে একই ।



0

আমি ভাবছি জাভা অনুমানের মধ্যে এমন কিছু আছে যা এই আচরণটি সঠিকভাবে সংজ্ঞায়িত করে। (এই বক্তব্যটির স্পষ্টতই বোঝা যাচ্ছে যে আমি চেক করতে খুব অলস।)

টমের বাইটোকোড থেকে নোট করুন, মূল রেখাগুলি হ'ল,, ৮ এবং ১১। লাইন the লোড এক্স এর গণনা স্ট্যাকের মধ্যে। লাইন 8 বৃদ্ধি x। লাইন 11 স্ট্যাক থেকে x এ ফিরে মান দেয়। আপনি যে মানগুলিকে নিজের কাছে ফিরিয়ে দিচ্ছেন না সেখানে আপনি লোড, স্টোর, ইনক্রিমেন্ট না করার কোনও কারণ থাকতে পারে বলে আমি মনে করি না। আপনি একই ফলাফল পাবেন।

পছন্দ করুন, ধরুন আপনার আরও স্বাভাবিক কেস হয়েছে যেখানে আপনি এমন কিছু লিখেছেন: z = (x ++) + (y ++);

তা বলে কিনা (সিডোকোড প্রযুক্তিবিধি এড়ানোর জন্য)

load x
increment x
add y
increment y
store x+y to z

অথবা

load x
add y
store x+y to z
increment x
increment y

অপ্রাসঙ্গিক হতে হবে। হয় বাস্তবায়ন বৈধ হওয়া উচিত, আমি মনে করি।

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


0

আমি মনে করি কারণ জাভাতে ++ এর = (অ্যাসাইনমেন্ট) এর চেয়ে বেশি অগ্রাধিকার রয়েছে ... তাই না? এ http://www.cs.uwf.edu/~eelsheik/cop2253/resources/op_precedence.html ...

আপনি একইভাবে যদি x = x + 1 লিখেন ... + এর = (অ্যাসাইনমেন্ট) এর চেয়ে বেশি অগ্রাধিকার রয়েছে


এটি প্রাধান্যের প্রশ্ন নয়। সি এবং সি ++ এর ++চেয়েও বেশি প্রাধান্য রয়েছে =তবে বিবৃতিটি অপরিজ্ঞাত।
ম্যাথু ফ্ল্যাশেন

0

x++অভিব্যক্তি মূল্যায়ণ x++অংশ পরে মান প্রভাবিত মূল্যায়ন পর না, বিবৃতি । তাই x = x++কার্যকরভাবে অনুবাদ করা হয়

int y = x; // evaluation
x = x + 1; // increment part
x = y; // assignment

0

এক দ্বারা মান বাড়ানোর আগে মানটি ভেরিয়েবলের জন্য বরাদ্দ করা হয়।


0

এটি পোস্ট বর্ধিত হওয়ার কারণে এটি হচ্ছে। এর অর্থ হল যে ভেরিয়েবলটি এক্সপ্রেশনটি মূল্যায়ন করার পরে বাড়ানো হয়।

int x = 9;
int y = x++;

এক্স এখন 10, তবে y 9, এক্স এর বৃদ্ধি হওয়ার আগে তার মান।

পোস্ট বৃদ্ধির সংজ্ঞাতে আরও দেখুন ।


1
আপনার x/ yউদাহরণটি বাস্তব কোড থেকে আলাদা এবং পার্থক্যটি প্রাসঙ্গিক। আপনার লিঙ্কটি জাভা সম্পর্কেও উল্লেখ করে না। ভাষায় এটা দুই জন্য নেই উল্লেখ, প্রশ্নে বিবৃতি undefined করা হয়।
ম্যাথু ফ্ল্যাশেন

0

নীচের কোডটি পরীক্ষা করুন,

    int x=0;
    int temp=x++;
    System.out.println("temp = "+temp);
    x = temp;
    System.out.println("x = "+x);

আউটপুট হবে,

temp = 0
x = 0

post incrementমানে মান বাড়ানো এবং বর্ধনের আগে মান ফেরত দেওয়া । কেন মান যে tempহয় 0। সুতরাং কি temp = iএবং যদি এটি একটি লুপ (কোডের প্রথম লাইন বাদে) থাকে। ঠিক প্রশ্নে !!!!


-1

বর্ধিত অপারেটরটি আপনি যেমন নির্ধারিত করছেন তেমন চলকটিতে প্রয়োগ করা হয়। এটা ঝামেলা চাইছে। আমি নিশ্চিত যে এই প্রোগ্রামটি চালানোর সময় আপনি আপনার এক্স ভেরিয়েবলের মান দেখতে পারবেন .... এটি কেন স্পষ্ট হওয়া উচিত যে লুপটি কখনই শেষ হয় না।

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