我需要包装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负位的转换时,位顺序。我不知道正确的行为应该是什么。

由于

有帮助吗?

解决方案

我喜欢乔伊亚当的回答除了它与宏(造成一个真正的痛苦在许多情况下)写的事实,编译器不会给你一个警告,如果“字符”不是1个字节宽。这是我的溶液(基于关乔伊的)。

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或C ++(标记为两个OP)工作。

其他提示

char不能保证被符号或无符号(在PowerPC的Linux,炭默认为无符号)。宣传!

你需要的是这样的宏:

#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);
}

我们的想法是,你看到“正确地转换所有的参数。按住Shift键并结合他们”,而不是“为每个参数,正确地将其转换,移位和结合起来”。没有多少,虽然。

然后:

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_tuint8_tint8_t类型作为便携式的。他们中没有需要在C99,并且头部stdint.h未在C ++或C89定义。如果存在类型,满足C99的要求,不过,该代码将工作。当然,在C中的解包功能将需要一个函数参数,而不是一个模板参数。你可能更喜欢在C ++太多,如果你想要写短环路拆包。

要解决的事实,类型是可选的,你可以使用uint_least32_t,这是在C99要求。同样uint_least8_tint_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的补码类型。

<强> “善”结果 恕我直言,这是你要获得这个最佳的解决方案。编辑:虽然我会使用static_cast<unsigned int>代替C风格的演员,我很可能不会使用一个单独的方法来隐藏投....

<强>可移植性:结果 这里将是这样做没有可移植的方法,因为没有人说char必须为8位,并没有说unsigned int必须是4个字节宽。

此外,您依靠端标记,并因此在一个体系结构数据pack'd将无法使用上一个与对面的端序。

<强>有没有现成的溶液,也许提高吗结果 这不是我所知道。

此是基于格兰特Peters和乔伊亚当斯的答案,延伸到显示如何解压符号值(解包的功能依赖于无符号值C中的模数规则):

(正如史蒂夫杰索普在注释中指出的那样,就没有必要单独pack_spack_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