programing

왜 무한 루프 상태가 되는 거죠?

copyandpastes 2022. 7. 3. 18:41
반응형

왜 무한 루프 상태가 되는 거죠?

다음 코드가 있습니다.

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

}

설명을 읽어보고 이해할 수 있도록...

주의: C#에서는 패스할 수 있기 때문에, 당초, 이 회답에 C# 코드를 게재했습니다.intref키워드를 지정합니다.구글에서 찾은 첫 번째 클래스를 사용하여 실제 합법 자바 코드로 업데이트하기로 했습니다.refC# 서 c 。그게 해답에 도움이 될지 해가 될지 잘 모르겠어요.저는 개인적으로 자바 개발을 그렇게 많이 하지 않았다고 말할 것입니다.그래서 제가 아는 한 이 점을 설명할 수 있는 더 많은 관용적인 방법이 있을 것입니다.


를 들어, '와 것을 할 수 있는 요?x++게게더 확확?

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

맞죠? 전달된 값을 증가시키고 원래 값을 반환합니다. 이것이 post increment 연산자의 정의입니다.

이제 이 동작이 예제 코드에서 어떻게 수행되는지 살펴보겠습니다.

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

postIncrement(x) incre? 증분 분증x네, 그리고 증가하기 전의 것을 반환합니다.이 반환값은 다음에 할당됩니다.x.

, 「」에 되어 있는 입니다.x1, 0 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먼저 x가 알 수 라고 헷갈립니다.은 아니다.x되어 있다y; 이것은 이전에 할당된 값입니다.실제로, 주입,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 x + 1, 그리고 다시0 x가 됩니다.


업데이트: 덧붙여서 다음과 같은 점을 의심하지 않도록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이 모두 불규칙하게 발생한다는 점에 유의하십시오.

백그라운드 스레드를 시작하는 중...
00110000000000101

x = x++작용합니다.

  • 을 평가합니다.x++ 식을 , 이x increment)및(증가전)를 실시합니다.x.
  • 을 '어울리다'에 합니다.x을 덮어씁니다 , 가된 、 ,된 、 가 , , , , , , 。

는 다음과 디컴파일된 이며, 디컴파일된 바이트 코드입니다.javap -c와 함께 : , , , ( ) :

8: iload_1 // 스택에 있는 x의 현재 값을 기억합니다.9: iinc 1, 1 // x 증가(스택은 변경되지 않음)12: istore_1 // 스택에서 x로 재메모된 값을 씁니다.

위해 「 」를 참조해 주세요.x = ++x:

8: iinc 1, 1 // x 증가11: iload_1 // x 값을 스택에 푸시합니다.12: icstore_1 // 스택에서 x로의 pop 값

은, 「」의이 「」이기 때문에 합니다.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
}

이제 Java VM은 스택 기반입니다. 즉, 각 작업에 대해 데이터가 스택에 푸시되고 스택에서 데이터가 튀어나와 작업을 수행합니다.또한 일반적으로 로컬 변수를 저장하는 배열인 다른 데이터 구조도 있습니다.로컬 변수에는 배열에 대한 인덱스인 ID가 지정됩니다.

연상법을 봅시다.main()★★★★

  • iconst_0 : 수값 。0스택에 푸시됩니다.
  • istore_1: 인덱스를 변수에 1
    , 「」입니다.x.
  • iload_1값: " " " 。1 that그의 이다.x, 「」입니다.0을 사용하다
  • iinc 1, 1 값: " " " "11x 이 now now now가 되다1.
  • istore_1: 의 값은 됩니다.「 」1그것은0 is is is is is 。x 증가된 값을 덮어씁니다.

에, 「」의 은 「」, 「」x는 변경되지 않고 무한 루프가 발생합니다.

  1. 프레픽스 표기법은 식을 평가하기 전에 변수를 증가시킵니다.
  2. 표현식 평가 후 포스트픽스 표기법이 증가합니다.

",,=의는 "보다.++

★★★★★★★★★★★★★★★★★.x=x++;과 같이

  1. x★★★★★★★★★★★★★★★★★★★★★★★★★★
  2. x
  3. 값 " " " "x 할당되어 있습니다.x.

어느 대답도 정확하지 않습니다.그러면, 다음과 같습니다.

을 when when when 를 쓸 때int x = x++ 를 하는 것이 .x값이 「새로운 값」을 하는 것입니다.x으로 하다x++ which of 값입니다x콜린 코크란의 대답에서 암시되었듯이.

재미삼아 다음 코드를 테스트합니다.

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

결과는 다음과 같습니다.

0
1

입니다.x 0.십.십.십.십.십.십.십.백.이 이 값을 읽습니다.x갱신된 값, 즉1 을 수신합니다.

그것은 이미 다른 사람들에 의해 잘 설명되었다.관련 Java 사양 섹션 링크만 포함하면 됩니다.

x = x++는 식입니다.Java는 평가 순서를 따릅니다.먼저 x++ 식을 평가하여 x를 증가시키고 결과 값을 이전 값인 x로 설정합니다.그런 다음 식 결과를 변수 x에 할당합니다.마지막에 x는 이전 값으로 돌아갑니다.

이 문장은 다음과 같습니다.

x = x++;

다음과 같이 평가합니다.

  1. x스택에 추가
  2. x;
  3. »x스택에서 가져옵니다.

따라서 값은 변경되지 않습니다.비교 대상:

x = ++x;

다음과 같이 평가됩니다.

  1. x;
  2. x스택에 추가
  3. »x스택에서 가져옵니다.

원하는 것은 다음과 같습니다.

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

답은 꽤 간단하다.사물이 평가되는 순서와 관련이 있습니다. x++합니다.x 후, 「」가 증분합니다.x.

결과, 식 、 현 、 현 、 현 、 consequ 、 consequ 、 consequ consequ consequ consequ 。x++0, 「」를 할당하고 것이군요x=0루프의 각 시간마다.입니다.x++는 이 값을 증가시키지만 할당 전에 이 값이 증가합니다.

http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html 에서

증가/감소 연산자는 피연산자 앞(prefix) 또는 피연산자 뒤에 적용할 수 있습니다.코드 result++; 및 ++result;는 둘 다 1씩 증가합니다.유일한 차이점은 프리픽스버전(++result)은 증가된 값으로 평가되지만 포스트픽스버전(result++)은 원래 값으로 평가됩니다.단순한 증감만 실행하는 경우 어떤 버전을 선택하든 상관없습니다.그러나 더 큰 식에 이 연산자를 사용하는 경우 선택한 연산자에 따라 상당한 차이가 있을 수 있습니다.

예를 들어, 다음을 시험해 보겠습니다.

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

그러면 1과 0이 출력됩니다.

무슨 일이 일어나고 있는지 알기 위해 기계 코드가 꼭 필요한 것은 아닙니다.

정의에 따라:

  1. 할당 연산자는 오른쪽 식을 평가하여 임시 변수에 저장합니다.

    1.1. x의 현재 값이 이 임시 변수로 복사됩니다.

    이제 1.2. x가 증가합니다.

  2. 그런 다음 임시 변수가 식 왼쪽(우연히 x)에 복사됩니다.그래서 x의 오래된 값이 다시 그 자체로 복사되는 것입니다.

그것은 꽤 간단하다.

사실상 다음과 같은 행동을 하게 됩니다.

  1. 오른쪽의 "결과"로서 x 값(0)을 잡다
  2. x의 값을 증가시킵니다(x는 1이 됩니다).
  3. 오른쪽(0으로 저장)의 결과를 x에 할당합니다(x는 현재 0).

이 개념은 해당 변수가 사용된 방정식에 사용할 값을 반환한 후 해당 변수가 증가한다는 것입니다.

편집: 코멘트로 인해 약간의 추가가 이루어지고 있습니다.이렇게 생각해 보세요.

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.

이 경우 절대 증가하지 않기 때문입니다. x++는 이

x = 0;

만약 이 한다면++x;이 값은 증가합니다.

으로 유지되기 때문입니다.그 이유는 값이x++는 0 이에요. 이 경우에는 x 여부에 은 """입니다x=0실행됩니다.이로 인해 일시적으로 증가된 값이 덮어쓰게 됩니다.x('1월 1일')은 1은 1월 1일.

이것은 당신이 기대하는 대로 작동합니다.프리픽스와 포스트픽스의 차이입니다.

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

x++는 증분 전의 X를 "반환"하는 함수 호출이라고 생각하십시오(그래서 이것이 사후 증분이라고 불립니다).

조작 순서는 다음과 같습니다.
x 후 증가시킨다1: 가기 x 을 1 1 1 。
: 증가 x2: 증가 x
값x을합니다.3: 캐시된 값(증가하기 전의 x)을 반환합니다.
됩니다: 반환값은 x4에 할당됩니다.

++가 rhs에 있으면 값이 증가하기 전에 결과가 반환됩니다.++x로 변경하시면 됩니다.Java는 증분이 아닌 단일 연산(x to x 할당)을 수행하도록 최적화했습니다.

이 에러는, 할당이 증가치를 덮어쓰기 해, 증가전의 값을 덮어쓰기 해, 즉 증가분을 원래대로 되돌리기 때문에 발생합니다.

특히, "x++" 식에는 "+x"가 증가하기 전에 "x" 값이 있고, "+x"는 증가 후에 "x" 값이 있습니다.

바이트 코드의 조사에 관심이 있는 경우는, 다음의 3 행에 대해 설명합니다.

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

두 번째 합니다.iload_1 # load 、 load 7 7 7 。
8:1.1 두 입니다!8: iinc 1.1#은 스택을 변경하지 . 스택은 변경되지 않은 상태로 유지됩니다.
# 이을 두 로컬 9: icstore_1 # 에 합니다.
(각 JVM 명령의 효과는 여기에서 확인할 수 있습니다.)

따라서 위의 코드는 무한정 루프되지만 ++x 버전에서는 루프되지 않습니다.++x의 바이트코드는 상당히 다르게 보일 것입니다.제가 1년 전에 작성한 1.3 Java 컴파일러에서 기억하기로는 바이트코드는 다음과 같습니다.

iinc 1,1
iload_1
istore_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;줄에 서 있는 것.

 x = x++; (increment is overriden by = )

위의 문장으로 인해 x는 3에 도달하지 않는다.

Java 스펙에 이 동작의 정확한 정의가 있는지 궁금합니다.(확인을 너무 게을러서 할 수긍할 수 없는 것이 분명합니다.)

Tom의 바이트 코드에 따르면 키 라인은 7, 8, 11입니다.7행은 x를 계산 스택에 로드합니다.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

무관해야 합니다.어느쪽이든 유효하다고 생각합니다.

이 동작에 따라 달라지는 코드를 작성하는 것은 매우 조심하고 싶습니다.구현에 매우 의존적인 것으로 보입니다.스펙의 크랙스 사이에 있는 것 같습니다.여기서와 같이 엉뚱한 행동을 했을 경우나 두 개의 스레드가 실행되고 식 내의 평가 순서에 의존했을 경우만 차이가 있습니다.

Java ++는 =(수정)보다 우선도가 높기 때문에...그런가요?http://www.cs.uwf.edu/ ~ 장어 / cop2253 / op_incellence . http://www.cs.uwf.edu/ 를 참조해 주세요.

x=x+1이라고 하는 것과 같은 방법으로...+가 =보다 우선 순위가 높습니다(기준).

x++ 표현하면 '아까운명하다.x . 。++부품은 평가 후 값에 영향을 미치지만 문장이 아닌 값에 영향을 미칩니다.x = x++으로 번역되다

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

값을 1씩 늘리기 전에 값이 변수에 할당됩니다.

포스트가 증가했기 때문에 일어나는 일입니다.표현식이 평가된 후 변수가 증가함을 의미합니다.

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

x는 10이지만 y는 9입니다.이 값은 증가하기 전의 x 값입니다.

자세한 내용은 포스트 인크리먼트의 정의를 참조해 주세요.

아래 코드를 확인합니다.

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

출력은 다음과 같습니다.

temp = 0
x = 0

post increment값을 증분하고 증분 전에 값을 반환함을 의미합니다.그래서 가치가 있는 것입니다.temp0 ★★★★★★★★★★★★★★★★★★★★★★★」temp = i이것은 루프에 있습니다(코드의 첫 번째 줄은 제외).★★★★★★★★!!!

증분 연산자는 할당하는 변수와 동일한 변수에 적용됩니다.그건 말썽을 부리는 거야.이 프로그램을 실행하는 동안 x 변수의 값을 볼 수 있을 것입니다.루프가 끝나지 않는 이유를 명확히 할 수 있을 거예요

언급URL : https://stackoverflow.com/questions/3831341/why-does-this-go-into-an-infinite-loop

반응형