erlang bit syntax에 대하여 #1

(bit syntax에 대해서는 더 공부해서 나중에 추가 포스팅을 할 요량으로 일단 제목에 ‘#1’을 붙였으나, 후속편은 언제 이어질지 장담할 수는 없습니다 :)

erlang에서는 <<>>로 감싸서 바이너리 데이터를 다루는데, <<“Hello World!>> 처럼 쓰면 C 언어에서의 char * 문자열과 같은 자료구조로 쓸 수 있고, 비트 단위로 쪼갤 수 있기 때문에 <<H, Rest/binary>> 처럼 bit syntax를 써서 바이너리 데이터를 쉽게 파싱할 수도 있다. 앞의 ‘Hello World!’ 문자열에 적용하면 첫 한 바이트를 얻을 수 있을 것이다.

1> <<H, Rest/binary>> = <<"Hello World!">>.
<<"Hello World!">>
2> H.
72
3> Rest.
<<"ello World!">>

만약 어떤 방법으로 IP 패킷을 받았다면 (Packet 변수에), 다음과 같이 한 번 실행에 손쉽게 IP 헤더를 분석할 수 있다.

<<IpVer:4, HLen:4, SvcType:8, TotLen:16, 
  Id:16, Flags:3, FragOff:13, TTL:8, Proto:8, HdrChkSum:16,
  SrcIP:32, DstIP:32, IpPayload/binary>> = Packet.

bit syntax를 보면 변수 명 뒤에 : 다음에는 얻어낼 바이너리 데이터의 비트 단위의 크기를 표시한다. 그래서 IpVer 변수에는 IP 헤더의 첫 4비트 필드의 값이 들어간다. 정상적인 IPv4 헤더라면 ‘4’ 값이 들어갈 것이다.

변수 명 뒤의 / 다음에는 해당 변수에 넣는 바이너리 데이터의 type을 나타낸다.  erlang reference manual을 참고하면 여기에는 다음 중 하나의 값을 사용할 수 있다. 생략할 경우 integer가 기본값이 된다.

Type = integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32

이외에도 signed/unsigned이나 endian 등을 더 명시할 수 있지만 다음에 다루기로 한다.

Type 중 binary, bytes, bitstring, bits에 대해 좀더 구분해보자면, 먼저 bytesbinary와 같고, bitsbitstring은 같은 것이다. 보다 짧게 표기하기 위한 것이다. binarybitstring은 데이터를 byte (즉 8 bit) 단위로 구분하느냐 bit 단위로 구분하느냐 차이이다. 아래 예의 경우 X에는 1이, Y에는 <<2,3,4>>가 매치된다.

1> <<X, Y/binary>> = <<1, 2, 3, 4>>.
<<1,2,3,4>>

그러나 아래처럼 X에 바이너리 데이터의 첫 7 bit를 매치시켜놓으면 나머지는 byte 단위로 딱 떨어지지 않고  25 bit가 되기 때문에 예외 에러가 발생한다.

1> <<X:7, Y/binary>> = <<1, 2, 3, 4>>.
** exception error: no match of right hand side value <<1,2,3,4>>

이 경우에는 X에 매치되는 데이터의 길이를 byte로 바로 잡든가, 아니면 아래와 같이 Y에 25 bit 데이터를 매치시키도록 type을 바꿔야 한다.

1> <<X:7, Y/bitstring>> = <<1, 2, 3, 4>>.
<<1,2,3,4>>
2> X.
0
3> Y.
<<129,1,130,0:1>>

X는 첫 7 bit만 읽었기 때문에 0이 매치됐고, Y의 경우 <<2, 3, 4>>가 1 bit 씩 오른쪽으로 쉬프트되는 꼴이 되어서 이진수로는 10000001, 00000001, 10000010, 0가 되어 위에서 표기된 것처럼 <<129, 1, 130, 0:1>>이 매치되었다.