본문
Big-endian
빅 엔디안 방식은 큰 값을 먼저 저장하는 방식이다. 예를 들어, 1234라는 숫자에서 1이 가장 중요한 숫자(MSB)가 되는 방식이다. 빅 엔디안에서는 이 작은 값이 메모리의 앞쪽에 저장되고, 작은 값(LSB)이 나중에 저장된다.
이 방식은 사람이 숫자를 읽는 방식과 동일하게 데이터를 저장하기 때문에, 디버깅이나 사람이 데이터를 직관적으로 이해하기에 매우 용이하다. 예를 들어, 32비트 정수 0x12345678을 빅 엔디안 방식으로 저장하면 메모리 상에 12 34 56 78 순서로 저장되며, 이는 우리가 숫자를 읽는 순서와 일치한다.
빅 엔디안 방식은 네트워크 프로토콜에서 표준적으로 사용되는데, 이를 "네트워크 바이트 오더"라고 부른다. 이 덕분에 네트워크 통신에서 일관성을 유지할 수 있으며, 다른 시스템 간의 데이터 교환 시 변환 과정 없이 바로 사용할 수 있다.
그러나 빅 엔디안 방식은 메모리에서 작은 단위로 데이터를 읽을 때 비효율적일 수 있다. 특히, x86과 같은 리틀 엔디안 아키텍처에서 빅 엔디안 데이터를 처리할 경우, 추가적인 변환 과정이 필요하므로 성능에 약간의 영향을 줄 수 있다.
Big Endian Parsing (1) - 16진수 배열에 특정 비트 추출하기
예를 들어, 다음과 같은 CAN Message가 Big Endian 방식으로 수신되었다고 가정해 보자. 이때 offset은 0이고 factor는 1이라고 가정한다. 여기서 5번 비트부터 12번 비트까지의 값은 얼마일까?
빅 엔디안은 큰 값이 먼저 저장되기 때문에 메모리엔 다음과 같이 저장될 것이다. 이때 특정 비트들의 값을 추출하는 것을 목적으로 하고 있으므로, 16진수를 2진수로 변환해 준다.
여기서 5번 비트부터 12번 비트까지 값을 추출하면 다음과 같다.
즉, 0000 0001(2) = 1(10)이다.
Big Endian Parsing (2) - 16진수 배열에 특정 비트 삽입하기
이번에는 빈 문자열 배열에 5번 비트부터 12번 비트까지 90이라는 10진수 값을 넣어 보자. Big Endian Parsing(1)과 마찬가지로 offset은 0이고 factor는 1이라고 가정한다. 그리고 각 문자열에 괄호로 된 숫자는 문자열 배열의 인덱스를 의미한다.
빅 엔디안 방식이므로 순서를 바꿔줄 필요가 없다. 특정 비트에 값을 넣기 위해 2진수로 변환해 주자.
그리고 아래와 같이 5번 비트부터 12번 비트까지 90을 2진수로 변환한 값인 0101 1010(2)을 차례대로 넣고 16진수로 변환해 보자.
여기서 바이트 순서를 반대로 적용하면 최종적으로 메시지는 다음과 같이 0x02, 0xD0, 0x00, 0x00으로 구성된다.
코드 구현
해당 내용을 Python 코드로 작성하면 다음과 같다. 파이썬의 문법을 크게 쓰지 않고 비트 연산이 주를 이루고 있기 때문에, 로직을 잘 파악하고 있다면 C언어로 변환하는 것도 크게 어렵지 않을 것이다.
def update_data_big_endian(data, value, start_bit, bit_length, factor):
value = int(value / factor)
data = bytearray(data)
for i in range(bit_length):
bit_value = (value >> (bit_length - 1 - i)) & 1
byte_index = (start_bit + i) // 8
bit_index = 7 - ((start_bit + i) % 8)
if bit_value:
data[byte_index] |= (1 << bit_index)
else:
data[byte_index] &= ~(1 << bit_index)
return data
message = [0x00, 0x00, 0x00, 0x00]
start_bit = 5
bit_length = 8
value = 90 # 0101 1010
updated_message = update_data_big_endian(message, value, start_bit, bit_length, 1)
print([hex(x) for x in updated_message])
def get_value_from_hex_big_endian(data, start_bit, bit_length, factor=1):
full_value = 0
for i in range(len(data)):
full_value |= data[i] << ((len(data) - 1 - i) * 8)
mask = (1 << bit_length) - 1
extracted_value = (full_value >> (len(data) * 8 - start_bit - bit_length)) & mask
return extracted_value * factor
if __name__ == "__main__":
message = [0x40, 0x0B, 0x00, 0x01]
start_bit = 5
bit_length = 8
factor = 1
extracted_value = get_value_from_hex_big_endian(message, start_bit, bit_length, factor)
print(f"Extracted Value: {extracted_value}")
print(f"Extracted Value (binary): {bin(extracted_value)}")
'CS > 임베디드' 카테고리의 다른 글
[임베디드] 신호와 주파수 (7) | 2024.10.08 |
---|---|
[임베디드] 엔디안 방식의 이해(1) with CAN Message (1) | 2024.09.26 |