Java가 서명되지 않은 정수를 지원하지 않는 이유는 무엇입니까?


374

Java가 부호없는 정수에 대한 지원을 포함하지 않는 이유는 무엇입니까?

예기치 않은 큰 입력에서 오버플로가 발생할 가능성이 적은 코드를 작성할 수 있다는 점을 감안할 때 이상한 생략 인 것 같습니다.

또한 부호없는 정수를 사용하는 것은 자체 문서화의 한 형태 일 수 있습니다. 부호없는 정수가 보유하려고 한 값이 절대 음수로 표시되지 않기 때문입니다.

마지막으로 부호없는 정수는 나누기와 같은 특정 작업에 더 효율적일 수 있습니다.

이것들을 포함하면 어떤 단점이 있습니까?


137
나는 모른다. 그러나 그것은 나에게서 지옥을 짜증나게한다. 예를 들어 이런 방식으로 네트워크 코드를 작성하는 것이 훨씬 어렵습니다.
Tamas Czinege

20
언어 / 데이터베이스 / ... 세계에 두 가지 유형 만 있었으면 좋겠다 : 숫자와 문자열 :)
Liao

5
네트워크 코드 작성은 그리 어렵지 않습니다. BTW InputStream.read ()는 부호없는 바이트가 아닌 부호없는 바이트를 반환하므로 네트워크 예제는 혼동 IMHO입니다. 서명 된 값을 작성하는 것이 서명되지 않은 값을 작성하는 것과는 다른 것으로 가정하는 것이 혼란 스럽습니다. 즉, 실제로 바이트 수준에서 무슨 일이 일어나고 있는지 모른다면.
Peter Lawrey

19
@ZachSaw-나는 언어 디자이너가 그 인용구를 보았을 때 이중 테이크 아웃을했다. 부호없는 정수보다 단순한 것은 없습니다. 부호있는 정수는 복잡합니다. 특히 트랜지스터 레벨에서 비트 트위들 링을 고려할 때. 그리고 부호있는 정수는 어떻게 이동합니까? Java 디자이너가 부울 논리를 이해하는 데 심각한 문제가 있다고 결론을 내 렸습니다.
PP.

8
나에게 그것은 이미지는 어떤 이미지 처리를 할 어려워진다 byte직선 줄 수없는 140그레이 레벨하지만를 -116당신이 할 필요가 & 0xff정확한 값을 얻을 수 있습니다.
Matthieu

답변:


193

이것은 단순성에 대한 Gosling 및 다른 사람들과인터뷰 에서 얻은 것입니다 .

Gosling : 저를 요즘으로 생각하지 않는 언어 디자이너로서 저에게 "간단한"이라는 의미는 J. Random Developer가 그의 머리 속에 스펙을 갖도록 기대할 수있었습니다. 예를 들어, Java는 그렇지 않다는 사실이 있습니다. 실제로 이러한 언어는 실제로 이해하지 못하는 많은 경우로 끝납니다. 서명되지 않은 C 개발자에 대한 퀴즈를 풀면 곧 C 개발자가 서명되지 않은 연산, 서명되지 않은 산술이 무엇인지 이해하는 사람이 거의 없다는 것을 알게 될 것입니다. 그런 것들이 C를 복잡하게 만들었습니다. Java의 언어 부분은 매우 간단하다고 생각합니다. 찾아야 할 라이브러리.


222
구체적인 예 (CLR에서)로 Gosling에 동의하지 않을 것입니다. 배열에 부호있는 정수 길이 값 또는 부호없는 길이를주는 것이 더 혼란 스럽습니까? 배열이 음의 길이를 갖는 것은 불가능하지만 API는 가능하다는 것을 나타냅니다.
JaredPar 2012 년

18
자바를 단순하게 만든다는 주장은 대안이 너무 번거롭기 때문에 결국 언어로 가져온 템플릿이 부족하여 우리를 혼란스럽게 만들었습니다. 이 프림 필요하지 않습니다,하지만 나는 하나가 적절한 클래스와 부호의 int를 지원할 수 있다고 생각하십니까
열린 우리당

59
배열 인덱스가 음수가 될 수 없어서 Java에 부호없는 정수가 필요한 경우 배열 인덱스가 배열 크기보다 클 수 없으므로 하위 범위 (라 파스칼)도 필요합니다.
Wayne Conrad

81
자, 그는 서명되지 않은 유형이 없다는 장점을 말했습니다. 이제 단점을 세어 보자 ...
Moshe Revah

83
언어 단순성보다 코드 단순성을 선호합니다. 내가 자바를 싫어하는 이유입니다.
Pijusn

50

선 사이를 읽으면 논리가 다음과 같다고 생각합니다.

  • 일반적으로 Java 디자이너는 사용 가능한 데이터 유형의 레퍼토리를 단순화하려고했습니다.
  • 일상적인 목적으로 서명 된 데이터 유형이 가장 일반적으로 필요하다고 느꼈습니다.
  • 특정 알고리즘을 구현하기 위해 부호없는 산술이 필요한 경우도 있지만 이러한 알고리즘을 구현할 프로그래머도 서명 된 데이터 유형으로 부호없는 산술을 수행하는 데 대한 지식이 있어야합니다.

대부분, 나는 그것이 합리적인 결정이라고 말했습니다. 아마도, 나는 :

  • 바이트를 부호없는 것으로 만들거나 적어도 하나의 데이터 유형에 대해 다른 이름을 가진 부호있는 / 부호없는 대안을 제공했습니다 (서명은 일관성을 유지하는 것이 좋지만 언제 부호있는 바이트가 필요합니까?)
  • '짧은'으로 없애 버렸습니다 (16 비트 부호있는 산술을 언제 마지막으로 사용 했습니까?)

그럼에도 불구하고 약간의 클루 징을 통해 최대 32 비트의 부호없는 값에 대한 작업은 그리 나쁘지 않으며 대부분의 사람들은 부호없는 64 비트 나누기 또는 비교가 필요하지 않습니다.


2
나는 부호없는 바이트를 갖고 싶지만 정수 유형 사이의 완전한 일관성의 이점이 부호없는 바이트가 가져 오는 편의성을 능가한다고 생각합니다.
Alan Moore

64
"일상적인 목적으로, 서명 된 데이터 유형이 가장 일반적으로 필요하다고 생각했습니다." 내 C ++ 코드에서 "왜 지구상에서 부호없는 정수 대신 부호있는 정수를 사용 하는가?!"라고 생각하는 경우가 많습니다. 나는 "서명 된"이 규칙이 아니라 예외라는 느낌을 가지고있다 (물론 도메인에 따라 다르지만 양의 정수가 자연수 라고 불리는 이유가있다 ;-)).
Luc Touraille

15
이미지 처리를 수행 할 때 부호가없는 바이트 (필요한 것으로 가정)를 가정 할 때 부호없는 바이트를 호출하기 위해 엄지 손가락을 올리면 디버깅에 몇 시간이 걸렸습니다.
Helin Wang

7
shortdefltate / gzip / inflate 알고리즘이 16 비트이고 얼마나 짧은 지에 크게 의존 short[]하고 있습니다. 후자 ( short[])는 int[]두 배 적은 메모리와 적은 메모리 = 더 나은 캐싱 특성, 훨씬 더 나은 성능을 갖기 때문에 상당한 이점이 있습니다.
bestsss

8
특정 응용 프로그램에서는 반바지를 사용하는 것이 사실이라고 가정하는 것보다 성능을 향상시키는 지 여부를 측정 해야 합니다. int (보통 프로세서가 '좋아요'를 사용하는 유형)가 아닌 short를 조작하는 데 필요한 여분의 농담이 실제로 특정 응용 프로그램의 성능에 해를 끼칠 수 있습니다. 항상 그런 것은 아니지만 가정하지 말고 테스트해야합니다.
Neil Coffey

19

이것은 오래된 질문이며 pat은 간단히 char을 언급했지만,이 길을 내려다 보는 다른 사람들을 위해 이것을 확장해야한다고 생각했습니다. Java 프리미티브 유형을 자세히 살펴 보겠습니다.

byte -8 비트 부호있는 정수

short -16 비트 부호있는 정수

int -32 비트 부호있는 정수

long -64 비트 부호있는 정수

char -16 비트 문자 (부호없는 정수)

하지만 char지원하지 않는 unsigned연산, 그것은 본질적으로 처리 할 수 있습니다 unsigned정수입니다. 산술 연산을 명시 적으로 다시로 캐스팅해야 char하지만 unsigned숫자 를 지정하는 방법을 제공합니다 .

char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ? 
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;

예, 부호없는 정수에 대한 직접적인 지원은 없습니다 (직접 지원이 있다면 대부분의 작업을 char로 다시 캐스팅 할 필요가 없습니다). 그러나 서명되지 않은 기본 데이터 유형이 반드시 존재합니다. 나는 부호없는 바이트도보고 싶었지만 메모리 비용을 두 배로 늘리고 대신 char을 사용하는 것이 가능한 옵션이라고 생각합니다.


편집하다

JDK8 거기위한 새로운 API는 다음 LongInteger헬퍼 메소드 제공하는 처리 longint부호 값으로 값.

  • compareUnsigned
  • divideUnsigned
  • parseUnsignedInt
  • parseUnsignedLong
  • remainderUnsigned
  • toUnsignedLong
  • toUnsignedString

또한 구아바 는 정수 유형에서 비슷한 작업을 수행하는 여러 가지 도우미 메서드를 제공하여 정수에 대한 기본 지원 부족으로 인한 격차를 해소 unsigned합니다.


2
그러나 예를 들어 산술 char을 지원하기에는 너무 작습니다 long.

3
이것은 Java의 단점 일 수 있습니다

바이트에 대해 부호없는 값을 지원하기를 바라고 있습니다. 일을 더 쉽게 만듭니다.
mixturez

15

Java에는 서명되지 않은 유형이 있거나 최소한 하나 이상이 있습니다. char는 부호가없는 축약 형입니다. 고슬링이 변명하는 것이 무엇이든지간에 서명되지 않은 다른 유형이없는 이유는 실제로 그의 무지입니다.

또한 짧은 유형 : 반바지는 멀티미디어에 항상 사용됩니다. 그 이유는 단일 32 비트 부호없는 길이로 2 개의 샘플을 맞추고 많은 연산을 벡터화 할 수 있기 때문입니다. 8 비트 데이터와 부호없는 바이트도 마찬가지입니다. 벡터화를 위해 레지스터에 4 개 또는 8 개의 샘플을 맞출 수 있습니다.


37
네, 고슬링은 당신에 비해 Java에 대해 무지하다고 확신합니다.
jakeboxer 2009

Java는 부호없는 바이트 수량에 대해 직접 산술을 수행 할 수 있습니까? 아니면 값이 항상 승격됩니까? 저장을 위해 서명되지 않은 유형을 가지지 만 항상 수용 할 수있을 정도로 큰 서명 된 유형에 대해 산술을 수행하면 의미 론적으로 잘 작동하지만 "정상"정수와 같은 크기의 서명되지 않은 유형에 대한 작업은 더 비쌀 수 있습니다.
supercat

2
char캐릭터 이외의 다른 스타일에는 사용 하기에 좋지 않습니다 .
starblue

5
@starblue 물론 그렇습니다. 그러나 언어의 한계를 극복하는 것은 해킹입니다
Basic

14

부호있는 정수와 부호없는 정수가 표현에 혼합되면 문제가 발생하기 시작하고 정보 손실 될 수 있습니다. 서명 된 정수로 Java를 제한하면 실제로 문제가 해결됩니다. 서명 된 / 서명되지 않은 전체 비즈니스에 대해 걱정할 필요가 없어서 기쁘지만, 때때로 바이트에서 8 비트를 놓치게됩니다.


12
부호있는 / 부호없는 믹싱에 대해 : 부호없는 유형을 가질 수 있지만 믹싱을 허용하지 않거나 명시 적 캐스트가 필요합니다. 여전히 필요한지 확실하지 않습니다.
sleske

2
C ++에서는 static_casts를 많이 뿌려서 혼합해야합니다. 정말 지저분합니다.
Raedwald

4
8 비트는 거기에 있으며, 그 자체를 기호로 숨기려고합니다.
starblue

32 비트 이상 유형에서는 문제가 발생합니다. Java가 bytePascal에서와 같이 서명 되지 않았을 이유가 없습니다 .
supercat

12
바이트가 부호없는 것으로 예상되는 Java의 이미지 처리에 문제가있을 때 저를 만나십시오. 그런 다음 & 0xFF'모든 바이트 대 INT 프로모션을 수행하면 코드가 더 복잡해집니다.
bit2shift 2016

12

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

이 표준은 C 표준이 서명되지 않은 및 서명 된 int와 관련된 연산을 서명되지 않은 것으로 취급하기 때문에 정의한다고 말합니다. 음의 부호있는 정수가 부호없는 큰 int로 롤오버되어 버그가 발생할 수 있습니다.


34
Java 부호있는 정수도 롤오버됩니다. 나는 당신의 요점이 보이지 않습니다.
foo

8
@foo : 부호있는 정수는 문제를 일으키기 전에 커져야합니다. 대조적으로, C에서는 음의 정수, 심지어 -1부호없는 양, 심지어 0을 비교하는 데 문제가있을 수 있습니다 .
supercat

Java가 서명되지 않은 유형을 포함 할 수는 없었지만 제한된 변환 세트와 혼합 연산자 (C에서 포인터를 5에 추가하는 방법과 비슷하지만 포인터를 5와 비교할 수는없는 것과 비슷합니다) . 묵시적 캐스트가 존재할 때 혼합 유형에서 연산자를 사용하면 캐스트를 내재적으로 사용하고 결과 유형으로 결과 유형을 사용해야한다는 아이디어는 .NET 및 .NET에서 많은 모호한 디자인 결정의 핵심입니다. 자바.
supercat

4
당신의 대답에 응하지 말고, -1"알 수없는"나이 (기사에서 암시하는 것처럼)를 갖는 것은 "코드 냄새"전형적인 예 중 하나입니다 . 예를 들어, "밥보다 앨리스가 얼마나 오래 되었습니까?", A = 25 및 B = -1을 계산하려는 경우 그에 대한 대답 ±26은 간단하지 않습니다. 알 수없는 값을 올바르게 처리하는 것은 일종의 반환 Option<TArg>시점 Some(25) - None입니다 None.
bytebuster

11

Java는 그대로 괜찮다고 생각하고 unsigned를 추가하면 많은 이익을 얻지 않고도 복잡하게 만들 수 있습니다. 단순화 된 정수 모델을 사용하더라도 대부분의 Java 프로그래머는 기본 숫자 유형의 작동 방식을 알지 못합니다. Java Puzzlers 라는 책을 읽고 어떤 오해가 생길 수 있는지 확인하십시오.

실용적인 조언에 관해서는 :

  • 값이 임의의 크기이며에 맞지 않으면를 int사용하십시오 long. long사용에 적합하지 않은 경우 BigInteger.

  • 공간을 절약해야 할 때 배열에만 더 작은 유형을 사용하십시오.

  • 정확히 64/32/16/8 비트가 필요한 경우 long/ int/ short/를 사용 byte하고 나누기, 비교, 오른쪽 이동 및 캐스팅을 제외하고 부호 비트에 대해 걱정하지 마십시오 .

"난수 생성기를 C에서 Java로 이식"에 대한 답변 도 참조하십시오 .


5
예, 바로 이동 당신은 사이에서 선택을해야 >>하고 >>>각각 서명 및 서명을 위해. 왼쪽으로 이동해도 문제 없습니다.
starblue

1
@starblue 실제로 및 >>>에서는 작동하지 않습니다 . 예를 들어, 보다는 yield . 다른 예 : 결과 . 물론 당신은 할 수 있지만 이것은 하나 이상의 연산을 추가합니다 (비트 &). shortbyte(byte)0xff>>>10x7fffffff0x7fbyte b=(byte)0xff; b>>>=1;b==(byte)0xffb=(byte)(b & 0xff >> 1);
CITBL

7
"... 간단한 모델을 사용하더라도 대부분의 Java 프로그래머는 기본 숫자 유형이 어떻게 작동하는지 알지 못합니다 ..."
기본

더 복잡하고 적은 이득에 대한 답변의 첫 줄은 6 년 후 기사에서 자세히 설명한 것입니다
Nayuki

1
@Nayuki 당신의 기사는 정말 좋습니다. 작은 말만으로, XOR 대신 비교 연산자에 0x80000000을 추가하여 사용하는 이유는 그것이 작동하는 이유를 설명하기 때문에 비교가 발생하는 연속 영역을 -MAXINT에서 0으로 이동합니다. 비트의 효과는 정확히 동일합니다.
starblue

6

JDK8 그것은 그들을 위해 어떤 지원을 가지고있다.

Gosling의 우려에도 불구하고 Java에서 서명되지 않은 유형을 완벽하게 지원할 수 있습니다.


12
일명 "사람들이 실제로 그것을 사용하고 시작하기 위해 그것을 포함하지 않는 것이 잘못되었습니다." VM에서 또는 서명 된 사촌과 동등한 유형으로
기본

6

이 게시물이 너무 오래되었다는 것을 알고 있습니다. 그러나 Java 8 이상에서는 int데이터 유형을 사용하여 최소값 0과 최대 값 2 32 -1 의 부호없는 32 비트 정수를 나타낼 수 있습니다 . 사용 Integer용도에 클래스 int부호없는 정수와 같은 정적 방법으로 데이터 타입 compareUnsigned(), divideUnsigned()등등에 부가 된 Integer부호없는 정수에 대한 산술 연산을 지원하는 클래스.


4

나는 그것들이 orignal Java 릴리스에 가깝게 포함되어야한다는 이야기를 들었습니다. Oak는 Java의 선구자였으며 일부 사양 문서에는 사용 된 값에 대한 언급이있었습니다. 불행히도 이것들은 결코 Java 언어로 만들지 않았습니다. 누구나 알아낼 수있는 한 시간 제약으로 인해 구현되지 않았습니다.


Gosling 인터뷰의 증거를 제외하고는 char디자이너가 언어의 목표를 고려할 때 나쁜 생각이라고 생각했기 때문에 부호가없는 정수 가 생략 되었다는 것을 암시합니다 .
Stephen C

다큐멘터리 증거도 가까이 있다면 목격자 진술에 너무 많은 가치를 두지 않는 것이 좋습니다.
user7610

4

나는 한 번 C ++ 표준위원회의 누군가와 함께 C ++ 과정을 밟았는데, 이는 서명되지 않은 정수를 사용하는 대부분의 프로그램이 부호있는 정수와 마찬가지로 할 수 있기 때문에 Java가 부호없는 정수를 피하기 위해 올바른 결정을 내렸다는 것을 암시했습니다. (2) 부호없는 정수를 사용하면 정수 산술 오버플로 및 부호있는 유형과 부호없는 유형 사이를 변환 할 때 중요한 비트를 잃는 것과 같은 문제를 쉽게 만들 수는 있지만 디버그하기가 어렵습니다. 부호있는 정수를 사용하여 실수로 0에서 1을 빼면 프로그램이 더 빨리 중단되고 2 ^ 32-1로 감싸는 것보다 버그를 쉽게 찾을 수 있으며 컴파일러 및 정적 분석 도구 및 런타임 검사는 서명되지 않은 산술을 사용하기로 선택한 이후에 수행중인 작업을 알고 있다고 가정합니다. 또한,

오래 전에 메모리가 제한되고 프로세서가 한 번에 64 비트에서 자동으로 작동하지 않았을 때 모든 비트가 더 많이 계산되었으므로 부호없는 바이트 또는 반바지와 부호를 갖는 것이 실제로 훨씬 더 중요한 문제였으며 분명히 올바른 설계 결정이었습니다. 오늘날 부호있는 int를 사용하는 것은 거의 모든 일반 프로그래밍 사례에서 충분하며 프로그램이 실제로 2 ^ 31-1보다 큰 값을 사용해야하는 경우 종종 길기를 원합니다. long을 사용하는 영역에 들어가면 2 ^ 63-1 양의 정수로 실제로 얻을 수없는 이유를 생각해내는 것이 더 어렵습니다. 128 비트 프로세서로 갈 때마다 별 문제가되지 않습니다.


2

귀하의 질문은 "자바가 부호없는 정수를 지원하지 않는 이유는 무엇입니까?"

그리고 귀하의 질문에 대한 나의 대답은 Java가 모든 기본 유형 인 byte , char , short , intlong 이 어셈블리에서와 마찬가지로 byte , word , dwordqword로 각각 처리되어야하며 Java 연산자가 서명 되기를 원한다는 것입니다. char를 제외한 모든 기본 유형의 연산 이지만 char 에서만 16 비트 부호가 없습니다.

따라서 정적 메소드는 것으로 가정 서명 동작을 32 및 64 비트에 대해.

서명되지 않은 작업에 대해 정적 메서드를 호출 할 수있는 최종 클래스가 필요 합니다.

이 최종 클래스를 생성하고 원하는 이름으로 호출하고 정적 메소드를 구현할 수 있습니다.

정적 메소드를 구현하는 방법에 대해 모른다면 이 링크 가 도움 이 될 수 있습니다.

내 의견으로는, 자바는 하지 ++ C와 유사한 전혀 이 경우, 어느 쪽도 서명되지 않은 유형 지원하지 않으며 연산자 오버로딩을 나는 자바는 모두 C에서 ++와 C는 전혀 다른 언어로 취급해야한다고 생각하므로,

그런데 언어의 이름도 완전히 다릅니다.

따라서 Java에서 C와 유사한 코드를 입력하는 것은 권장하지 않으며 C ++과 유사한 코드를 입력하지 않는 것이 좋습니다 .Java에서는 C ++에서 다음에 수행하려는 작업을 수행 할 수 없기 때문에, 즉, 코드는 전혀 C ++이 아니며 계속 나에게 스타일을 변경하는 것은 좋지 않습니다.

서명 된 연산에도 정적 메소드를 작성하고 사용하는 것이 좋습니다. 따라서 코드에 서명 된 연산 만 필요하지 않은 한 부호있는 연산과 서명되지 않은 연산 모두에 대한 연산자와 정적 메소드의 코드 혼합을 볼 수 없으며 괜찮습니다. 연산자 만 사용하십시오.

또한 short , intlong 기본 유형을 사용 하지 말고 각각 word , dwordqword를 대신 사용하는 것이 좋습니다. 연산자 대신 서명되지 않은 작업 및 / 또는 서명 된 작업에 대한 정적 메서드를 호출하는 것입니다.

서명 된 연산 만 수행하고 코드에서만 연산자를 사용하려는 경우 이러한 기본 유형을 short , intlong 사용하는 것이 좋습니다 .

실제로 word , dwordqword 는 언어에 존재 하지 않지만 각각에 대해 새 클래스를 만들 수 있으며 각각의 구현은 매우 쉽습니다.

클래스 워드 는 기본 유형을 짧게 유지하고 클래스 dword 는 기본 유형을 int 만 보유하고 qword 클래스 는 기본 유형을 길게 보유합니다 . 이제 모든 부호없는 메소드와 부호있는 메소드가 정적이거나 선택하지 않은 것처럼 각 클래스에서 구현 할 수 있습니다. 즉, 부호없는 단어 와 부호있는 클래스의 의미 이름을 지정하여 부호없는 문자 와 부호있는 모든 16 비트 연산을 서명 할 수 있습니다. dword 클래스 에 의미 이름을 제공하여 부호가 있고 qword 클래스 에 의미 이름을 제공하여 부호가없고 부호있는 모든 64 비트 연산이 있습니다 .

각 방법에 대해 너무 많은 다른 이름을주고 마음에 들지 않으면, 당신은 항상 자바 않았다 읽고, 자바에 과부하를 잘 사용할 수 없는 것을 너무 제거!

8 비트 부호있는 조작에 대한 연산자가 아닌 메소드와 전혀 연산자가없는 8 비트 부호없는 조작에 대한 메소드가 필요한 경우 Byte 클래스를 작성할 수 있습니다 (첫 번째 문자 'B'는 대문자 임). primitive type byte ) 및이 클래스의 메소드를 구현하십시오.

값으로 전달 및 참조로 전달 정보 :

C #에서와 같이 내가 틀리지 않으면 기본 객체는 자연스럽게 값으로 전달되지만 클래스 객체는 자연스럽게 참조로 전달되므로 Byte , word , dwordqword 유형의 객체는 값이 아닌 참조로 전달됩니다 기본적으로. Java가 C #에서와 같이 구조체 객체를 가지기를 바랍니다. 따라서 모든 Byte , word , dwordqword클래스 대신 구조체 로 구현할 수 있습니다.따라서 기본 유형과 같이 C #의 모든 struct 객체는 기본적으로 참조가 아닌 값으로 전달되지만 Java는 C #보다 나쁘기 때문에 기본적으로 참조가 아닌 값으로 전달되었습니다. 이를 처리하기 위해 기본적으로 값이 아닌 참조로 전달되는 클래스와 인터페이스 만 있습니다. 따라서 Java 및 C #의 다른 클래스 객체와 같이 Byte , word , dwordqword 객체를 참조가 아닌 값 으로 전달 하려면 복사 생성자를 사용하면됩니다.

그것이 내가 생각할 수있는 유일한 솔루션입니다. 필자는 기본 유형을 단어, dword 및 qword로 typedef 할 수 있기를 원하지만 Java 는 C의 typedef와 동일한을 사용 하는 C #과 달리 typedef를 사용하거나 전혀 사용하지 않습니다 .

출력 정보 :

동일한 비트 시퀀스의 경우 여러 가지 방법 으로 비트 를 인쇄 할 수 있습니다. 2 진 (C printf의 % u와 같은 의미), 8 진 (C printf의 % o와 같은 의미), 16 진 (예 : C printf에서 % x의 의미) 및 정수 (C printf에서 % d의 의미)

C printf는 함수에 매개 변수로 전달되는 변수의 유형을 알지 못하므로 printf는 함수의 첫 번째 매개 변수에 전달 된 char * 객체에서만 각 변수의 유형을 알고 있습니다.

따라서 Byte , word , dwordqword 각 클래스에서 print 메소드를 구현하고 printf의 기능을 얻을 수 있습니다. 클래스의 기본 유형이 서명 된 경우에도 관련 알고리즘을 따라 서명되지 않은 상태로 인쇄 할 수 있습니다 논리 및 시프트 연산을 사용하여 숫자를 출력으로 인쇄합니다.

불행히도 내가 준 링크는 이러한 인쇄 방법을 구현하는 방법을 보여주지 않지만 이러한 인쇄 방법을 구현하는 데 필요한 알고리즘을 Google에서 찾을 수 있다고 확신합니다.

그게 내가 당신의 질문에 대답하고 당신에게 제안 할 수있는 전부입니다.


MASM (Microsoft 어셈블러) 및 Windows는 BYTE, WORD, DWORD, QWORD를 부호없는 유형으로 정의합니다. MASM, SBYTE, SWORD, SDWORD, SQWORD의 경우 서명 된 유형입니다.
rcgldr

1

unsigned유형은 순수한 악 이기 때문입니다.

C에서 unsigned - int생산 한다는 사실 unsigned은 훨씬 더 악하다.

다음은 한 번 이상 나를 태운 문제의 스냅 샷입니다.

// We have odd positive number of rays, 
// consecutive ones at angle delta from each other.
assert( rays.size() > 0 && rays.size() % 2 == 1 );

// Get a set of ray at delta angle between them.
for( size_t n = 0; n < rays.size(); ++n )
{
    // Compute the angle between nth ray and the middle one.
    // The index of the middle one is (rays.size() - 1) / 2,
    // the rays are evenly spaced at angle delta, therefore
    // the magnitude of the angle between nth ray and the 
    // middle one is: 
    double angle = delta * fabs( n - (rays.size() - 1) / 2 ); 

    // Do something else ...
}

아직 버그를 발견 했습니까? 디버거를 시작한 후에 만 ​​보았습니다.

n부호없는 유형 이므로 size_t전체 표현식이로 n - (rays.size() - 1) / 2평가됩니다 unsigned. 그 표현은 중간 광선으로부터의 광선 의 부호있는 위치 가되도록 의도된다 n: 좌측의 중간 광선으로부터의 제 1 광선은 위치 -1을 가질 것이고, 오른쪽의 제 1 광선은 위치 +1을 가질 것이다. abs 값을 취하고 delta각도를 곱하면 n광선과 중간 광선 사이의 각도를 얻을 수 있습니다.

불행히도 위의 표현에는 악의 부호가없고 -1로 평가하는 대신 2 ^ 32-1로 평가되었습니다. 후속 변환으로 double버그 가 봉인되었습니다.

unsigned산술 을 잘못 사용하여 발생하는 버그 하나 또는 두 개가 발생 하면 여분의 비트가 얻는 것이 추가 문제의 가치가 있는지 궁금해하기 시작해야합니다. unsigned이진 마스크와 같은 비 산술 연산에 여전히 유형을 사용하지만 산술에서 유형의 사용을 피하기 위해 가능한 한 많이 노력 하고 있습니다.


"부호없는 long"을 Java에 추가하는 것은 어색합니다. 그러나 더 작은 부호없는 유형을 추가해도 아무런 문제가 없습니다. 특히 "int"보다 작은 유형은 숫자로 명백한 방식으로 "int"로 승격 시켜서 쉽게 처리 할 수 ​​있었으며, "intsigned int"는 부호있는 int 및 unsigned int와 관련된 연산이 두 피연산자는 모두 "long"입니다. 유일한 피연산자 상황은 부호없는 long과 부호있는 수량을 포함하는 연산입니다. 두 피연산자의 모든 값을 나타낼 수있는 유형이 없기 때문입니다.
supercat

@ supercat : 모든 작업에서 unsigned변환되는 경우 int무엇을 사용 unsigned합니까? 와 구별되는 기능이 없습니다 short. 당신이 변환 할 경우 int에만 같은 혼합 작업에 unsigned+int또는 unsigned+float, 당신은 여전히 문제가 ((unsigned)25-(unsigned)30)*1.0 > 0의 주요 원인이다 unsigned- 관련 버그를.
Michael

서명되지 않은 유형에 대한 많은 작업은 "긴"으로 승격됩니다. 결과를 부호없는 유형으로 다시 저장할 때 명시 적 캐스트를 요구하면 short 및 byte에서 존재하는 것과 거의 동일한 성가심이 발생하지만 유형이 주로 계산 형식이 아닌 저장 형식 인 경우 문제가되지 않습니다. 어쨌든 "int"보다 짧은 부호없는 유형은 어려움없이 "int"로 승격 할 수 있어야합니다.
supercat

3
이 답변은 "부호없는 정수는 사악하고 결코 서명 할 수 없기 때문에 존재해서는 안됩니다"라는 인수를 사용하기 때문에 싫어합니다. 부호없는 정수에서 빼려고하는 사람은 이것을 이미 알고 있어야합니다. 가독성에 관해서는, C는 따르기 쉬운 것으로 정확하게 알려져 있지 않습니다. 더욱이, (반) 인수 "추가 비트는 추가 문제의 가치가 없습니다"또한 매우 약합니다. 오류 처리가 exit(1);실제로 '추가 문제 발생'입니까? 경험이 적은 자바 프로그래머가 사용하지 않는 보안의 가치가있는 큰 파일을 실제로 열 수 unsigned없습니까?
yyny

2
이 코드에서 볼 수있는 유일한 악의는 n - (rays.size() - 1) / 2입니다. 코드 판독기는 컴퓨터 프로그램의 작업 순서에 대해 아무 것도 가정 할 필요가 없으므로 항상 이진 연산자를 대괄호로 묶어야합니다. 우리가 일반적으로 a + b c = a + (b c)라고해서 코드를 읽을 때 이것을 가정 할 수있는 것은 아닙니다. 또한 루프 외부에 테스트 할 수 있도록 루프 외부에서 계산을 정의해야합니다. 이것은 부호없는 정수 문제가 아니라 타입을 정렬하지 않는 버그입니다. C에서는 타입을 정렬해야합니다.
Dmitry

0

'C'스펙에는 자바가 실용적으로 떨어졌지만 개발자 요구 (클로저 등)로 서서히 되돌아 오는 몇 가지 보석이 있습니다.

이 토론과 관련이 있기 때문에 첫 번째를 언급합니다. 부호없는 정수 산술에 대한 포인터 값의 준수 그리고이 스레드 주제와 관련하여 서명 된 Java 세계에서 서명되지 않은 의미론을 유지하기가 어렵습니다.

고든 링의 디자인 팀에게 데니스 리치에게 다른 자아를 갖기 위해 서명하면 "무한도의 제로"를 줄 것을 제안했을 것입니다.

이렇게하면 배열에서 발생하는 오프셋은 절대 SEGFAULT를 생성 할 수 없습니다. 예를 들어, "자체 순환 루프"컨텍스트에서 서명되지 않은 동작을 필요로하는 Double의 RingArray를 호출하는 캡슐화 된 클래스에서 :

// ...
// Housekeeping state variable
long entrycount;     // A sequence number
int cycle;           // Number of loops cycled
int size;            // Active size of the array because size<modulus during cycle 0
int modulus;         // Maximal size of the array

// Ring state variables
private int head;   // The 'head' of the Ring
private int tail;   // The ring iterator 'cursor'
// tail may get the current cursor position
// and head gets the old tail value
// there are other semantic variations possible

// The Array state variable
double [] darray;    // The array of doubles

// somewhere in constructor
public RingArray(int modulus) {
    super();
    this.modulus = modulus;
    tail =  head =  cycle = 0;
    darray = new double[modulus];
// ...
}
// ...
double getElementAt(int offset){
    return darray[(tail+modulus+offset%modulus)%modulus];
}
//  remember, the above is treating steady-state where size==modulus
// ...

위의 RingArray는 악의적 인 요청자가 시도한 경우에도 절대 인덱스에서 절대 'get'하지 않습니다. 이전 (음수) 색인 값을 요청하는 합법적 인 요청도 많이 있습니다.

NB : 외부 % 모듈러스는 합법적 인 요청을 역 참조하지만 내부 % 모듈러스는-모듈러스보다 더 음인 네거티브로부터 뻔뻔한 악의를 가려냅니다. 이것이 Java + .. + 9 || 8 + .. + 사양이라면 문제는 '실제로'자체 회전 '할 수없는 프로그래머'가 될 것입니다.

소위 Java unsigned int 'deficiency'는 위의 한 줄짜리로 보완 될 수 있다고 확신합니다.

추신 : 위의 RingArray 하우스 키핑에 컨텍스트를 제공하기 위해 위의 'get'요소 작업과 일치하는 후보 'set'작업이 있습니다.

void addElement(long entrycount,double value){ // to be called only by the keeper of entrycount
    this.entrycount= entrycount;
    cycle = (int)entrycount/modulus;
    if(cycle==0){                       // start-up is when the ring is being populated the first time around
        size = (int)entrycount;         // during start-up, size is less than modulus so use modulo size arithmetic
        tail = (int)entrycount%size;    //  during start-up
    }
    else {
        size = modulus;
        head = tail;
        tail = (int)entrycount%modulus; //  after start-up
    }
    darray[head] = value;               //  always overwrite old tail
}

-2

불행한 부작용 하나를 생각할 수 있습니다. Java 임베디드 데이터베이스에서 32 비트 ID 필드로 가질 수있는 ID 수는 2 ^ 32가 아닌 2 ^ 31입니다 (~ 40 억이 아닌 ~ 20 억).


1
아마도 배열을 생각하고 음수를 인덱스로 사용할 수 없습니다. 아마.
SK9

2
데이터베이스의 자동 증가 필드가 오버플로되면 종종 엉망이됩니다.
여호수아

-8

IMHO는 그 실수를 이행 / 수정하기에는 너무 게으 르기 때문입니다. C / C ++ 프로그래머가 부호없는, 구조, 공용체, 비트 플래그를 이해하지 못한다고 제안하는 것은 단지 터무니없는 일입니다.

Ether 당신은이 언어를 전혀 알지 못하고 la C 프로그래밍을 시작하기 직전에 기본 / bash / java 프로그래머와 이야기하고 있거나 자신의 마음에서 이야기하고 있습니다. ;)

파일이나 하드웨어에서 매일 형식을 다룰 때, 무엇을 생각하고 있는지 궁금해지기 시작합니다.

여기서 좋은 예는 부호없는 바이트를 자체 회전 루프로 사용하는 것입니다. 마지막 문장을 이해하지 못하는 사람들을 위해 지구상에서 어떻게 자신을 프로그래머라고 부릅니다.

DC


34
차기 만하면 구글은 "자체 회전 루프"라는 문구를 씁니다. 분명히 , Denis Co는 자신을 스스로 프로그래머라고 부를 가치가있는 유일한 사람입니다.
Stephen C

6
이 답변은 너무 나쁘기 때문에 재미있다
Nayuki
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.