2010-01-15 5 views
1

는 전 C#로 마이그레이션하려고 자바 프로그래머 해요,이 날 약간 난처한 상황에 빠진 잡았다 :비트 단위 또는 long으로의 암시 적 캐스트가있는 것 같습니다. 피할 수 있습니까?

int a = 1; 

a = 0x08000000 | a; 
a = 0x80000000 | a; 

첫 번째 줄은 잘 컴파일합니다. 두 번째는 그렇지 않습니다. 부호 비트와 일정이 있음을 인식하는 것, 그리고 어떤 이유로이 오류의 결과로, 긴에 결과를 캐스팅하기로 결정 :

Cannot implicitly convert type 'long' to 'int'.
An explicit conversion exists (are you missing a cast?)

지금까지이 수정은 다음과 같습니다

Bitwise-or operator used on a sign-extended operand;
consider casting to a smaller unsigned type first

은 무엇 오류/경고/길이없는 방식으로이를 표현하는 올바른 C#을 방법이 될 것입니다 : 여전히 캐스트 다루고 있지만

a = (int)(0x80000000 | a); 

는 경고를 남긴다?

답변

12

숫자의 정수는, 기본적으로 int입니다.

0x80000000 값이 너무 커서 int에 맞지 않으므로 uint 값입니다. intuint에서 | 연산자를 사용하면 두 값 모두 long으로 확장되지 않으므로 안전하게 다른 쪽으로 변환 할 수 없습니다.

값은 int로 표시 될 수 있지만 음수 값이된다는 것을 무시해야합니다. 컴파일러는 자동으로 그렇게하지 않을 것이다, 그래서 당신은 오버 플로우에 대해 걱정하지 않고 값 int을하도록 지시해야한다 :

a = unchecked((int)0x80000000) | a; 

(참고 :이 방법 만 값을 변환하는 컴파일러에 지시합니다, 그래서 거기에). int로의 전환을하고 생성 더 코드입니다

+0

아니요,'uint'입니다 : http://msdn.microsoft.com/en-us/library/aa664674%28VS.71%29.aspx – Joey

+0

사실, 그것은 가장 깨끗한 수정처럼 보입니다. 감사. – izb

+0

많은 마스크가 있기 때문에 코드 정리가 필요합니다. private const int MASK_80000000 = 선택 안 함 ((int) 0x80000000); – izb

1

0x80000000은 int 형식의 빼기 값이며 마이너스 값에 대해서는 비트 단위 연산을 수행 할 수 없기 때문에 문제가 발생합니다.

uint를 사용하면 정상적으로 작동합니다.

a = ((uint)0x80000000) | a; //assuming a is a uint 
+0

는''0x80000000' 이미 uint'는 사양에 따라된다 : http://msdn.microsoft.com/en-us/library/aa664674%28VS.71%29.aspx – Joey

+0

즉 아무런 차이가 없다 나는 두려워. – izb

+6

이 설명은 위조입니다. 음의 정수에서 비트 연산을 수행 할 수 있습니다. –

1


(int)((uint)0x80000000 | (uint)a);
에 그 라인을 변경 나를 위해 그것을 않습니다. 숫자가 int에 맞게 너무 커서 대신 (등등 longulong의 경우) uint됩니다 않는 문자

+0

그 트릭을 할 것으로 보인다 :) 그 캐스트는 런타임 비용으로 온다면 누구든지 알아? 아니면 컴파일러가 모든 것을 정돈 해 줍니까? – izb

+2

기본 런타임 시스템은 int와 uint를 구별하지 않습니다. 그것은 단지 32 비트 양동이입니다. 캐스트는 아무 것도 할 수 없게됩니다. –

0

당신이 가지고있는 문제는

  • 0x80000000부호 정수 리터럴 것입니다. 명세에 따르면 정수 리터럴은 리터럴을 담을 수있는 첫 번째 유형 (int, uint, long, ulong)입니다. 이 경우는 uint입니다.
  • a 아마int

이것은 결과long되도록 입니다. a이 (-)이 될 수 없다는 것을 알지 못한다면 결과를 int으로 다시 캐스트하는 것 이외에 더 좋은 방법은 없습니다. 그런 다음 auint으로 전송하거나 처음부터 그렇게 선언 할 수 있습니다.

12

이 모든 대답에서 실제로 한 사람이이 말한 것을 수행하는 을 제안했습니다. 경고는 문제를 해결하는 방법을 알려줍니다. 그것에주의를 기울이십시오.

Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first

비트 확장 또는 연산자가 부호 확장 피연산자에 사용됩니다. int. 이로 인해 결과는 더 긴 유형으로 변환됩니다. long보다 작은 부호없는 유형은 uint입니다. 경고가 말하는 것을 그렇게하십시오; 부호 확장 된 피연산자를 int 형으로 캐스팅합니다.

result = (int)(0x80000000 | (uint) operand); 

이제 부호 확장이 없습니다.

물론 이것은 더 큰 질문을 제기합니다. 왜 처음에는 부호가있는 정수를 비트 필드로 취급합니까? 이것은 위험한 일처럼 보입니다.

0

문자 'O'로 시작하는 상수를 만들어 추악하지 않게 만들 수 있습니다. (이 웹 사이트와 달리 Visual Studio에서는 다른 색상으로 표시하지 않습니다.)

const int Ox80000000 = unchecked((int)0x80000000); 

/// ... 

const int every /* */ = Ox80000000; 
const int thing /* */ = 0x40000000; 
const int lines /* */ = 0x20000000; 
const int up /*  */ = 0x10000000;