2017년 2월 18일 토요일

[java][byte] 0xff 누구냐 넌!

제목에만 적어놓고 언젠가 적어야지 적어야지 했던 글을 이제야 적는다.
자바를 사용할 때 가끔 0xff를 사용해야 할 때가 있다. 없다고? 음... 그렇다면 당신 대신 누군가 해준 것이니 모른다는 것에 감사하시길...

혹시 unsigned int와 singed int를 아는지? 아아 아주 단순한 문제이니 대답을 해주겠다.
unsigned int : 사인(부호)이 안되어있는 int값
signed int : 사인(부호)이 있는 int값
좀 더 자세히 말하면 부호가 있는 int값과 없는 값 둘로 나뉜다. 그렇다면 자바에서 사용하는 int는 무슨 값일까?

???
모를 수도 있고 알 수도 있다. 비전공자인 나로썬 뭔말인가 싶었다. 하지만 다 정보처리기사에 나오니 걱정하지말라. 누가 물으면 이렇게 말해라.
'그거 정보처리기사에서 다 공부했죠.'
자바에는 int건 byte건 unsigned란 없다. signed만을 (이렇게 해서 설계를 잘했다고 하는 강의도 본 적이 있는데 난 허접이라 잘 모르겠다.) 사용한다. 맞다. 부호가 있는 숫자를 사용한단 말이다. 부호가 없는 int는 사용하지 않는다. 뭐야? 그럼 우리가 알 필요가 없잖아??
유감스럽게도 아니다
왜냐하면 세상은 unsigned int로 이루어진 것들이 꽤나 있기 때문이다. 일단 그렇게 사용하던 코드들이 있고 가장 중요한 것은 이 값은 바이트 타입으로 받았을 때이다.
한 번 바이트 타입으로 127 이상으로 값을 넣어보자.
public static void main(String[] args) {
  byte[] a = new byte[] {127, 0, 0, 1};
  byte[] b = new byte[] {128, 0, 0, 1};
}
a는 되고 b는 안된다. 삶과 죽음은 종이한장 차이라더니, 1의 차이가 프로그램을 아예 실행할 수 없게 만들고 있다.
왜그럴까?
바로 자바는 항상 부호가 있는 숫자이기 때문이다.
바이트는 8비트다. 8비트이면 256개를 표현할 수 있는데, 왜 128이 안된다는 것일까?
잘 생각하자 우리는 부호가 있는 값을 이용한다.
256을 반으로 뚝 잘라라


128 | 128 오!! 되잖아!!! 라고 말 할 줄 알았다. 여기서 한 놈은 1을 빼야한다.
왜? 0을 누군가는 표기해야 하니까.
지금은 그래서 0000 0000 이놈이 0을 표현하게 되는데 이 0이 누구꺼냐는 거다.
결론을 말하면 자바 바이트 타입은 -128 ~ 127 이렇게 표현할 수 있다. 그러니 128은 표현할 수 없는 존재가 되는 것이다.
public static void main(String[] args) {
  byte[] b = new byte[] {(byte)128 , 0, 0, 1};
  System.out.println( (byte) 128 );
}
이거 마이너스가 뜬다. 왜냐하면, 128은 int다. 그걸 바이트로 내가 지금 강제로 형변환을 했다. 128은 2의 7승이다. 그 말은 1000 0000 이다.

일단 맨 앞에 1이 있으면 부호가 음수이다.

public static void main(String[] args) {
  byte[] b = new byte[] {(byte)128 , 0, 0, 1};
  System.out.println( (byte) 128 );
  System.out.println((byte) 128 & 0xff);
}
바로 우리가 알아봐야 할 0xff 누구냐넌! 이놈은 이렇게 생겼다. 쟤는 16진수라는 거다.
잠깐 나가지말고 들어보라. 정말 별거 아니니까!!!
0x는 16진수 앞에 붙는 기호라고 하고.
f는 15을 뜻한다.
f가 두개다. 이것 이런 말이다. 15*16^1 + 15*16^0 이거 한번 계산기를 돌려보자.
System.out.println(15*16 + 15*1);
이건 255가 나온다. 255? 어디서 많이 들어 본 것 같지 않은지? 맞다. 우리 네트워크 설정할 때 많이 사용한다. 바로 그 때!!!! 사용되고 있을 지도 모르는 놈이 0xff이다.

여튼 이놈을 이용해서 &(and)연산을 하면 부호가 없는 없는 그냥 숫자가 나올 것이다. (왜?)
잘 생각해보자. 255는 일단 부호가 있는 숫자에서 255라는 숫자가 나온것이다.
그러면 잘 생각해보자.
기호가 없는 255는 1111 1111 이다. 기호가 있는 255는? 무조건 앞이 0이다. 게다가 255는 int라니까? 부호가 있는 32비트다. 32비트!!!
0000 0000 0000 0000 0000 0000 1111 1111
0xff의 정체이다. 자 그런데 어떻게 저 (byte) 128 & 0xff 가 어떻게 되는거지?
자!! 이제 얼마 안남았다.
1111 1111 1111 1111 1111 1111 1111 1111 1000 0000
0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 (and) 연산 실시
----------------------------------
0000 0000 0000 0000 0000 0000 0000 0000 1000 0000
이러면 이제, 부호가 마이너스가 아니라! 부호가 플러스인 128라는 숫자가 된다.
휴... 금방 끝날 줄 알았는데... 하... 힘들었다.


이 글이 정말 서툴지만 누군가에게는 많은 정보가 되길 바랍니다. 그리고 잘못 적은 내용을 지적해주신 분께 감사의 뜻을 전합니다. ^^

댓글 2개:

  1. 캬.. 앱 개발중에
    알림함수 setColor 값이 0xff 로 시작해서 넣으라길레
    이게 뭔가 하고 찾아보다 오게됬는데, 좋은글 올려주셔서 감사합니다.
    잘보고 갑니다~

    답글삭제