왜 int i = 1024 * 1024 * 1024 * 1024가 오류없이 컴파일됩니까?
제한은 int
-2147483648에서 2147483647입니다.
입력하면
int i = 2147483648;
Eclipse는 "2147483648"아래에 빨간색 밑줄을 표시합니다.
그러나 내가 이것을하면 :
int i = 1024 * 1024 * 1024 * 1024;
잘 컴파일됩니다.
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
아마도 Java의 기본 질문 일 수도 있지만 두 번째 변형이 왜 오류가 발생하지 않는지 모르겠습니다.
그 진술에는 아무런 문제가 없습니다. 4 개의 숫자를 곱하고 int에 할당하면 오버플로가 발생합니다. 이것은 컴파일 타임에 바운드 검사되는 단일 리터럴을 할당하는 것과 다릅니다 .
할당이 아닌 오류를 일으키는 것은 범위를 벗어난 리터럴 입니다 .
System.out.println(2147483648); // error
System.out.println(2147483647 + 1); // no error
대조적으로 long
리터럴은 잘 컴파일됩니다.
System.out.println(2147483648L); // no error
사실, 결과는 다음 사항을주의 되어 있기 때문에 여전히 컴파일 시간에 계산 1024 * 1024 * 1024 * 1024
A는 상수 표현 :
int i = 1024 * 1024 * 1024 * 1024;
된다 :
0: iconst_0
1: istore_1
결과 ( 0
)는 단순히로드 및 저장되며 곱셈이 발생하지 않습니다.
에서 JLS §3.10.1 (코멘트에서 그것을 양육에 대한 @ChrisK 덕분에) :
유형의 십진 리터럴
int
이2147483648
(2 31 ) 보다 크 거나 십진 리터럴2147483648
이 단항 빼기 연산자의 피연산자 ( §15.15.4 ) 이외의 다른 곳에 나타나면 컴파일 타임 오류 입니다.
1024 * 1024 * 1024 * 1024
그리고 2147483648
자바에서 같은 값이 없습니다.
사실, 2147483648
심지어 값이 아닌 (비록 2147483648L
자바이다). 컴파일러는 말 그대로 그것이 무엇인지 또는 어떻게 사용하는지 모릅니다. 그래서 울린다.
1024
Java의 유효한 int이며 유효한 valid int
에 다른 valid을 곱한 값 int
은 항상 valid int
입니다. 계산이 오버플로되기 때문에 직관적으로 기대하는 것과 같은 값이 아닌 경우에도 마찬가지입니다.
예
다음 코드 샘플을 고려하십시오.
public static void main(String[] args) {
int a = 1024;
int b = a * a * a * a;
}
이것이 컴파일 오류를 생성 할 것으로 예상됩니까? 이제 조금 더 미끄러 워집니다.
반복을 3 번 반복하고 루프를 곱하면 어떻게 되나요?
컴파일러는 최적화 할 수 있지만 그렇게하는 동안 프로그램의 동작을 변경할 수 없습니다.
이 사건이 실제로 어떻게 처리되는지에 대한 정보 :
Java 및 기타 여러 언어에서 정수는 고정 된 비트 수로 구성됩니다. 주어진 비트 수에 맞지 않는 계산은 오버플로됩니다 . 계산은 기본적으로 Java에서 계수 2 ^ 32로 수행 된 후 값이 부호있는 정수 로 다시 변환됩니다 .
다른 언어 또는 API는 동적 비트 수 ( BigInteger
Java)를 사용하거나 예외를 발생 시키거나 값을 숫자가 아닌 마법의 값으로 설정합니다.
두 번째 변형이 왜 오류가 발생하지 않는지 모르겠습니다.
The behaviour that you suggest -- that is, the production of diagnostic message when a computation produces a value that is larger than the largest value that can be stored in an integer -- is a feature. For you to use any feature, the feature must be thought of, considered to be a good idea, designed, specified, implemented, tested, documented and shipped to users.
For Java, one or more of the things on that list did not happen, and therefore you don't have the feature. I don't know which one; you'd have to ask a Java designer.
For C#, all of those things did happen -- about fourteen years ago now -- and so the corresponding program in C# has produced an error since C# 1.0.
In addition to arshajii's answer I want to show one more thing:
It is not the assignment that causes the error but simply the use of the literal. When you try
long i = 2147483648;
you'll notice it also causes a compile-error since the right hand side still is an int
-literal and out of range.
So operations with int
-values (and that's including assignments) may overflow without a compile-error (and without a runtime-error as well), but the compiler just can't handle those too-large literals.
A: Because it is not an error.
Background: The multiplication 1024 * 1024 * 1024 * 1024
will lead to an overflow. An overflow is very often a bug. Different programming languages produce different behavior when overflows happen. For example, C and C++ call it "undefined behavior" for signed integers, and the behavior is defined unsigned integers (take the mathematical result, add UINT_MAX + 1
as long as the result is negative, subtract UINT_MAX + 1
as long as the result is greater than UINT_MAX
).
In the case of Java, if the result of an operation with int
values is not in the allowed range, conceptually Java adds or subtracts 2^32 until the result is in the allowed range. So the statement is completely legal and not in error. It just doesn't produce the result that you may have hoped for.
You can surely argue whether this behavior is helpful, and whether the compiler should give you a warning. I'd say personally that a warning would be very useful, but an error would be incorrect since it is legal Java.
'IT' 카테고리의 다른 글
쉼표 연산자는 무엇을합니까? (0) | 2020.06.11 |
---|---|
팬더의 특정 열 인덱스에 열을 어떻게 삽입합니까? (0) | 2020.06.11 |
Java 클래스에서 선언 된 정적 필드 만 검색 (0) | 2020.06.11 |
사용 가능한 플레이 북에서 하나의 작업 만 실행하는 방법은 무엇입니까? (0) | 2020.06.11 |
멤버를 수동으로 폐기하는 방법 (0) | 2020.06.11 |