Endianness 라는 개념이 있다.
보통 Big-endian과 Little-endian 두 가지가[각주:1] 있는데, 메모리에 여러 바이트 연속된 자료가 저장되는 순서를 말한다.
다른 표현으로는 바이트 오더(Byte Order)라고도 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | // Reverses the byte order in unsigned integer value. // For example, 0x12345678 becomes 0x78563412. __STATIC_FORCEINLINE uint32_t __REV( uint32_t value ){ #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) return __builtin_bswap32( value );#else uint32_t result; __ASM volatile ( "rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG ( value ) ); return result;#endif } // Reverses the byte order within each halfword of a word. // For example, 0x12345678 becomes 0x34127856. __STATIC_FORCEINLINE uint32_t __REV16( uint32_t value ) { uint32_t result; __ASM volatile ( "rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG ( value ) ); return result;} // Reverses the byte order in a 16-bit value and returns the signed 16-bit result. // For example, 0x0080 becomes 0x8000. __STATIC_FORCEINLINE int16_t __REVSH( int16_t value ){ #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) return ( int16_t )__builtin_bswap16( value );#else int16_t result; __ASM volatile ( "revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG ( value ) ); return result;#endif } |
회사에서 Cortex-M4[각주:2]로 장비를 만드는데, 이 환경에는 위와 같이 바이트 오더를 바꾸는 CPU 함수들이 있다.
이에 따라 프로토콜에서 바이트 오더가 바뀌어야 하면 적절한 함수만 호출하면 된다.
Big-endian과 Little-endian 외에 Middle-endian도 지원할 수 있도록 내장(intrinsic) 함수들을 만들어뒀다.
x86/x64 환경에서는 이런 CPU 명령이 있을리가 없다고 믿어 직접 만들기로 했다.
1 2 3 | constexpr uint16_t __REVSH( uint16_t n) noexcept { return ((n >> 8) | (n << 8)); } |
그런데, 좀 예쁘지(?) 않아서 좀 바꿔보기로 했다.
이를 위한 매크로도 충실하게 준비되어 있다.
1 2 3 | constexpr uint16_t __REVSH( uint16_t n) noexcept { return MAKEWORD(LOBYTE(n), HIBYTE(n)); } |
그리고는 정상적으로 동작하지 않았고, 망했다[...]
위 함수는 인자의 순서를 잘못 기술해서, 뒤집어지지 않고, 입력값을 그대로 출력해준다...
아래와 같이 작성해야 맞다.
1 2 3 | constexpr uint16_t __REVSH( uint16_t n) noexcept { return MAKEWORD(HIBYTE(n), LOBYTE(n)); } |
여기에 시간을 허비하고나서 다시 생각하니, 근본적으로 접근 방법이 틀린 것이다.
이런 함수는 내가 만들 필요가 없이 만들어져 있는 것을 활용하면 된다.
일단 치사하게는(?) 아래와 같이 하는 방법도 있다.
1 2 3 4 5 | #include <WinSock2.h> uint16_t __REVSH( uint16_t n) { return htons(n); } |
그런데, 이건 바람직한 방법이 아니다.
소켓을 사용하지 않는 경우도 있을 수가 있고, 근본적으로 htons()의 목적이 이게 아니기 때문이다.
이 함수의 목적은 Little/Endian 데이터를 무조건 Big-endian으로 바꾸는 것이라 미묘하게 다르다.
게다가, 성능도 느린 편이다.
이 정도 고민했을 때 뭔가 쌔한 느낌이 들었다.
아니, 설마 SIMD가 판치는 요즘 x86/x64 CPU에서 이런 기능이 없다고?
찾아보니 당연히 있었다[...]
80486 이전 CPU에서는 없던 명령이라는 친절한 설명도 있었고[...]
그리고, 역시 당연히 이를 위한 intrinsic 함수도 만들어져 있었다.
선언은 intrinc.h 및 stdlib.h에 되어있고...
1 2 3 | unsigned short _byteswap_ushort( unsigned short value );unsigned long _byteswap_ulong( unsigned long value );unsigned __int64 _byteswap_uint64( unsigned __int64 value ); |
결론적으로, Cortex-M4 환경과 동일한 함수를 사용하려면 아래와 같이 선언하면 된다.
1 2 3 4 5 6 7 8 9 10 11 | uint16_t __REVSH( uint16_t n) { return _byteswap_ushort(n);} uint32_t __REV( uint32_t n) { return _byteswap_ulong(n);} uint32_t __REV16( uint32_t n) { return (((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00)); } |
e의 연분수 전개시 특정 수렴값의 분자의 합 (0) | 2020.11.08 |
---|---|
제곱근의 연분수 전개시 반복되는 숫자가 홀수 개인 경우는? (0) | 2020.11.08 |
n 제곱의 자릿수가 n인 경우의 개수는? (0) | 2020.03.28 |
정공법으로 소수 판별 시 더 빠른 방법은? (0) | 2020.03.28 |
대각선에서 소수의 비율이 10% 이하가 되는 값 찾기 (0) | 2020.03.26 |
내 블로그 - 관리자 홈 전환 |
Q
Q
|
---|---|
새 글 쓰기 |
W
W
|
글 수정 (권한 있는 경우) |
E
E
|
---|---|
댓글 영역으로 이동 |
C
C
|
이 페이지의 URL 복사 |
S
S
|
---|---|
맨 위로 이동 |
T
T
|
티스토리 홈 이동 |
H
H
|
단축키 안내 |
Shift + /
⇧ + /
|
* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.