الكاتب | وسيم
رئيس التحرير | Guo Rui
أعتقد أن معظمكم يعرف الفرق بين i ++ و ++ i ، i ++ هو استخدام i أولاً ، ثم الزيادة بمقدار 1 ، و ++ i هو الزيادة بمقدار 1 ، ثم استخدام i. على سبيل المثال ، بالنسبة للبيانين التاليين ، يمكنني أن أضمن أن معظم الناس سيفعلون:
int i = 1 ؛ System.out.println (i ++) int i = 1 ؛ System.out.println (++ 1)الإجابات هي 1 ، 2 وأعتقد أن معظم الناس يمكنهم الإجابة على هذه الإجابة. ولكن كيف يتم تنفيذ العمليتين i ++ و ++ i داخليًا؟
دعونا نلقي نظرة على سؤال آخر أولاً:
الفراغ الثابت العام الرئيسي (سلسلة السلاسل) {
int i = 1 ؛
System.out.println (i +++ i ++) ؛
System.out.println (i) ؛
}}
هذا أصعب قليلاً من الإجابة السابقة ، والإجابات 3 و 3. إذا كنت تعرف أصل هذه الإجابة جيدًا ، فيجب ألا تنظر إلى أسفل. إذا كنت لا تفهم هذه العملية أو تريد فهمها من أسفل إرشادات التجميع ، فيمكنك حينئذٍ الاطلاع على تفسيري.
بادئ ذي بدء ، دعونا نلقي نظرة على سؤال i ++ ، بشكل أساسي من أجل تفسير جيد لاحقًا.
int i = 1 ؛
System.out.println (i ++) ؛
تعليمات التجميع الجزئي لهذين السطرين من التعليمات البرمجية هي كما يلي. لاحظ أنني سردت بعض عبارات التجميع الرئيسية فقط:
ICONST_1 // قم بتحميل الثابت 1 إلى أعلى المكدس
ISTORE 1 // قم بفتح العنصر في أعلى المكدس وقم بتعيينه للمتغير مع الموضع "1" في جدول المتغير المحلي ، والذي يشير إلى المتغير i. هذه الجملتان تعادل int i = 1 ؛
// Next تنفيذ السطر الثاني من التعليمات البرمجية
ILOAD 1 // قم بتحميل المتغير بالموضع "1" في جدول المتغيرات المحلية إلى أعلى المكدس ، أي قم بتحميل قيمة i إلى أعلى المكدس
IINC 11 // أضف 1 مباشرة إلى المتغير الذي يكون موضعه "1" في جدول المتغيرات المحلية ، أي أضف 1 إلى i. لاحظ أن هذه التعليمات تزيد i بدون تعديل مكدس المعامل.
INVOKEVIRTUAL java / io / PrintStream.println (I) V // اطبع العنصر في أعلى المكدس ، وفي هذا الوقت يكون العنصر في أعلى المكدس 1. لذلك تطبع 1
لذلك ، يتم طباعة 1 في هذا الوقت.
قد لا يقوم بعض الأشخاص بتجميع التجميع قليلاً ، فلا بأس. سأقضي بعض الوقت في رسم صورة لمحاكاة (ملاحظة: تم حذف العديد من التفاصيل).
يظهر الجدول المتغير المحلي ومكدس المعامل في البداية في الشكل:
1. تنفيذ ICONST_1 ، يتم دفع الثابت 1 إلى المكدس:
2. تنفيذ ISTORE 1 ، ويتم تفريغ العنصر العلوي من المكدس وتخزينه في الموضع "1":
3. قم بتنفيذ ILOAD 1 ، واحفظ القيمة المتغيرة في الموضع "1" في أعلى المكدس:
4. قم بتنفيذ IINC 11 وأضف المتغير مباشرة بالموضع "1" في جدول المتغيرات المحلية بمقدار 1:
5. قم بتنفيذ INVOKEVIRTUAL java / io / PrintStream.println (I) V لطباعة العناصر في أعلى المكدس. في هذا الوقت ، العنصر في الجزء العلوي من المكدس هو 1:
لذا على الرغم من أن i يساوي 2 بالفعل ، فإن العنصر الموجود في الجزء العلوي من المكدس هو الآن القيمة قبل i ، لذا تتم طباعة 1.
هل تفهم i ++ الآن؟
دعونا نلقي نظرة على الفرق بين تعليمات التجميع لـ ++ i و i ++.
int i = 1 ؛ System.out.println (++ i) ؛تعليمات تجميع المفاتيح المقابلة هي كما يلي:
// إنه مشابه لـ i ++ أعلاه ، ولكن تم عكس ترتيب IINC 11 و ILOAD 1.
ICONST_1
ISTORE 1
IINC 11 // أضف 1 مباشرة إلى المتغير الذي يكون موضعه "1" في جدول المتغيرات المحلية
ILOAD 1 // اضغط على المتغير في الموضع "1" أعلى المكدس ، في هذا الوقت العنصر في الجزء العلوي من المكدس هو 2
INVOKEVIRTUAL java / io / PrintStream.println (I) V // لذا فإن الطباعة هي 2
ثم ارسم الصورة التالية لتوضيح:
1. المتغيرات والمكدسات المحلية بعد تنفيذ ICONST_1 و ISTORE 1 هي كما يلي:
2. تنفيذ IINC 11. لاحظ أنه عند تنفيذ هذه التعليمات ، لن يتغير مكدس المعامل:
3. تنفيذ ILOAD 1 ، ودفع القيمة المتغيرة في الموضع "1" إلى أعلى المكدس:
4. قم بتنفيذ INVOKEVIRTUAL java / io / PrintStream.println (I) V لطباعة العنصر في أعلى المكدس. في هذا الوقت ، العنصر الموجود في الجزء العلوي من المكدس هو 2:
لذا ، افهم الفرق بين i ++ و ++ i.
بعد ذلك ، دعنا نحلل هذا البرنامج:
int i = 1 ؛
System.out.println (i +++ i ++) ؛
System.out.println (i) ؛
دعني أتحدث عن ذلك أولاً ، وفقًا لترتيب الأولوية للرموز الحسابية ، فإن i +++ i ++ يعادل (i ++) + (i ++).
تعليمات التجميع الجزئي المقابلة هي كما يلي:
//السطر الاول
ICONST_1
ISTORE 1
//السطر الثاني
ILOADAD 1
IINC 11
ILOADAD 1
IINC 11
IADD // بعد ظهور وإضافة العنصرين في الجزء العلوي من المكدس ، ضع النتيجة مرة أخرى في الجزء العلوي من المكدس
INVOKEVIRTUAL java / io / PrintStream.println (I) V
// الصف الثالث
ILOADAD 1
INVOKEVIRTUAL java / io / PrintStream.println (I) V
إذا فهمت طريقتين i ++ و ++ i أعلاه ، فيجب أن يكون التجميع أعلاه مفهوما تقريبًا. دعني أحللها واحدة تلو الأخرى باستخدام الرسوم البيانية.
1. الحالة بعد تنفيذ ICONST_1 و ISTORE 1 هي كما يلي:
2. تنفيذ ILOAD 1:
3. تنفيذ IINC 11:
4. تنفيذ ILOAD 1:
5. تنفيذ IINC 11:
في هذا الوقت ، قيمة i هي في الواقع 3 ، ولكن القيمة القديمة لـ i موجودة في أعلى المكدس.
6. قم بتنفيذ IADD ، وأضف العنصرين العلويين من المكدس ، ثم ضع النتيجة على المكدس:
7. تنفيذ INVOKEVIRTUAL java / io / PrintStream.println (I) V ، في هذا الوقت العنصر العلوي من المكدس هو 3 ، وبالتالي فإن الطباعة هي 3:
8. قم بتنفيذ ILOAD 1 لتحميل جدول المتغيرات المحلية في أعلى المكدس:
9. تنفيذ INVOKEVIRTUAL java / io / PrintStream.println (I) V ، في هذا الوقت العنصر العلوي من المكدس هو 3 ، وبالتالي فإن الطباعة هي 3:
تم الانتهاء من!
الآن بعد أن عرفت ، أعرف أيضًا كيف أفعل i +++++ i وما يحدث.
تركز هذه المقالة على السماح لك بفهم آلية تنفيذ i ++ و ++ i. للحصول على إرشادات التجميع أعلاه وعملية التكديس والتراص ، من أجل شرح أفضل للمشكلة التي سيتم حلها ، يتم إخفاء العديد من التفاصيل ، ويتم أيضًا حذف جزء من التعليمات البرمجية. إذا كان هناك أي أخطاء ، يرجى أن يغفر لي.
إذا كنت تريد معرفة المزيد عن تعليمات التجميع ، فأنا أرى ملخصًا هنا: https://blog.csdn.net/hudashi/article/details/7062675.
تنويه: هذا المقال مقدم من المؤلف ، وحق المؤلف له.