문제

4 개의 서명 된 바이트를 32 비트 적분 유형에 포장해야합니다. 이것이 제가 다음과 같은 것입니다.

int32_t byte(int8_t c) { return (unsigned char)c; }

int pack(char c0, char c1, ...) {
  return byte(c0) | byte(c1) << 8 | ...;
}

이것이 좋은 해결책입니까? 휴대용 (통신 의미가 아님)입니까? 기성품 솔루션이 있습니까?

내가 주로 걱정하는 문제는 음의 비트를 숯에서 int로 변환 할 때 비트 순서입니다. 나는 올바른 행동이 무엇인지 모른다.

감사

도움이 되었습니까?

해결책

나는 조이 아담의 대답을 좋아했습니다. 매크로 (많은 상황에서 진짜 고통을 유발하는)로 작성된 사실을 제외하고는 'char'가 1 바이트 너비가 아닌 경우 컴파일러가 경고를하지 않습니다. 이것은 내 해결책입니다 (Joey의 기반).

inline uint32_t PACK(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) {
    return (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
}

inline uint32_t PACK(sint8_t c0, sint8_t c1, sint8_t c2, sint8_t c3) {
    return PACK((uint8_t)c0, (uint8_t)c1, (uint8_t)c2, (uint8_t)c3);
}

C0-> C3을 UINT32_T로 캐스팅하는 것을 생략했습니다. 컴파일러가 이동할 때 컴파일러를 처리해야하며 C 또는 C ++ (OP 태그로 표시된 OP 태그)에서 작동 할 때 C 스타일 캐스트를 사용했습니다.

다른 팁

char 서명 또는 서명되지 않은 것이 보장되지 않습니다 (PowerPC Linux에서 Char defaults 서명되지 않았습니다). 말씀을 전하십시오!

당신이 원하는 것은이 매크로와 같은 것입니다.

#include <stdint.h> /* Needed for uint32_t and uint8_t */

#define PACK(c0, c1, c2, c3) \
    (((uint32_t)(uint8_t)(c0) << 24) | \
    ((uint32_t)(uint8_t)(c1) << 16) | \
    ((uint32_t)(uint8_t)(c2) << 8) | \
    ((uint32_t)(uint8_t)(c3)))

C의 운영 순서와 잘 어울리지 않기 때문에 주로 추악합니다. 또한, 백 슬래시 리턴이 있으므로이 매크로는 하나의 큰 긴 줄이 될 필요가 없습니다.

또한 UINT32_T에 캐스팅하기 전에 UINT8_T에 캐스트 한 이유는 원치 않는 부호 확장을 방지하기 때문입니다.

암시 적 전환으로 캐스트를 피할 수 있습니다.

uint32_t pack_helper(uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3) {
    return c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
}

uint32_t pack(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) {
    return pack_helper(c0, c1, c2, c3);
}

아이디어는 "모든 매개 변수를 올바르게 변환합니다. 각 매개 변수에 대해 전환하고 결합하십시오"라는 것이 "각 매개 변수에 대해 올바르게 변환하고 이동하고 결합하십시오"라는 것입니다. 그래도 그다지 많지는 않습니다.

그 다음에:

template <int N>
uint8_t unpack_u(uint32_t packed) {
    // cast to avoid potential warnings for implicit narrowing conversion
    return static_cast<uint8_t>(packed >> (N*8));
}

template <int N>
int8_t unpack_s(uint32_t packed) {
    uint8_t r = unpack_u<N>(packed);
    return (r <= 127 ? r : r - 256); // thanks to caf
}

int main() {
    uint32_t x = pack(4,5,6,-7);
    std::cout << (int)unpack_u<0>(x) << "\n";
    std::cout << (int)unpack_s<1>(x) << "\n";
    std::cout << (int)unpack_u<3>(x) << "\n";
    std::cout << (int)unpack_s<3>(x) << "\n";
}

산출:

4
5
249
-7

이것은 휴대용입니다 uint32_t, uint8_t 그리고 int8_t 유형. C99에는 필요하지 않으며 헤더 stdint.h는 C ++ 또는 C89에 정의되어 있지 않습니다. 그러나 유형이 존재하고 C99 요구 사항을 충족하면 코드가 작동합니다. 물론 C에서는 포장 풀기 기능에 템플릿 매개 변수 대신 함수 매개 변수가 필요합니다. 포장을 풀기 위해 짧은 루프를 작성하려면 C ++에서도 선호 할 수 있습니다.

유형이 선택 사항이라는 사실을 해결하기 위해 사용할 수 있습니다. uint_least32_t, C99에서 필요합니다. 비슷하게 uint_least8_t 그리고 int_least8_t. pack_helper 및 unpack_u의 코드를 변경해야합니다.

uint_least32_t mask(uint_least32_t x) { return x & 0xFF; }

uint_least32_t pack_helper(uint_least32_t c0, uint_least32_t c1, uint_least32_t c2, uint_least32_t c3) {
    return mask(c0) | (mask(c1) << 8) | (mask(c2) << 16) | (mask(c3) << 24);
}

template <int N>
uint_least8_t unpack_u(uint_least32_t packed) {
    // cast to avoid potential warnings for implicit narrowing conversion
    return static_cast<uint_least8_t>(mask(packed >> (N*8)));
}

솔직히 말해서 이것은 그만한 가치가 없을 것 같지 않습니다. 나머지 신청서는 int8_t 등이 있습니다. 8 비트와 32 비트 2의 보완 유형이없는 드문 구현입니다.

"선량"
IMHO, 이것은 당신이 얻을 수있는 최고의 솔루션입니다. 편집 : 나는 사용할 것입니다 static_cast<unsigned int> C 스타일 캐스트 대신에, 나는 아마도 캐스트를 숨기기 위해 별도의 방법을 사용하지 않을 것입니다 ....

이식성 :
아무 말도하지 않기 때문에 휴대용 방법이 없을 것입니다. char 8 비트 여야하며 아무 말도하지 않습니다 unsigned int 너비가 4 바이트 여야합니다.

또한, 당신은 엔디 언에 의존하고 있으므로 하나의 아키텍처에 대한 데이터 팩은 반대의 엔디네스와 하나에서 사용할 수 없습니다.

기성품 솔루션이 있습니까?
내가 알고있는 것은 아닙니다.

이는 Grant Peters와 Joey Adams의 답변을 기반으로하며, 서명 된 값을 풀리는 방법을 보여주기 위해 확장되었습니다 (포장되지 않은 함수는 C에서 서명되지 않은 값의 모듈로 규칙에 의존합니다).

(Steve Jessop이 의견에 언급했듯이 별도의 필요는 없습니다. pack_s 그리고 pack_u 함수).

inline uint32_t pack(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3)
{
    return ((uint32_t)c0 << 24) | ((uint32_t)c1 << 16) |
        ((uint32_t)c2 << 8) | (uint32_t)c3;
}

inline uint8_t unpack_c3_u(uint32_t p)
{
    return p >> 24;
}

inline uint8_t unpack_c2_u(uint32_t p)
{
    return p >> 16;
}

inline uint8_t unpack_c1_u(uint32_t p)
{
    return p >> 8;
}

inline uint8_t unpack_c0_u(uint32_t p)
{
    return p;
}

inline uint8_t unpack_c3_s(uint32_t p)
{
    int t = unpack_c3_u(p);
    return t <= 127 ? t : t - 256;
}

inline uint8_t unpack_c2_s(uint32_t p)
{
    int t = unpack_c2_u(p);
    return t <= 127 ? t : t - 256;
}

inline uint8_t unpack_c1_s(uint32_t p)
{
    int t = unpack_c1_u(p);
    return t <= 127 ? t : t - 256;
}

inline uint8_t unpack_c0_s(uint32_t p)
{
    int t = unpack_c0_u(p);
    return t <= 127 ? t : t - 256;
}

(이것은 단순히 주조하는 것보다 필요합니다. int8_t, 후자는 값이 127을 초과하면 구현 정의 신호가 증가 할 수 있으므로 휴대용이 아닙니다).

컴파일러가 당신을 위해 일을하도록 할 수도 있습니다.

union packedchars {
  struct {
    char v1,v2,v3,v4;
  }
  int data;
};

packedchars value;
value.data = 0;
value.v1 = 'a';
value.v2 = 'b;

등.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top