【问题标题】:Convert 64bit Int to Char[] (and back)将 64 位 Int 转换为 Char[](并返回)
【发布时间】:2015-09-19 03:45:00
【问题描述】:

我编程我想将一个大端数组(我相信因为我在 Mac 上,整数将是小端)字符(或者更确切地说是 uint8_ts)转换为 int64_t 并返回。这是我的代码:

int64_t CharsToInt(uint8_t* chars) {
    return chars[0] + (chars[1] * 0x100) + (chars[2] * 0x10000) + (chars[3] * 0x1000000) + (chars[4] * 0x100000000) + (chars[5] * 0x10000000000) + (chars[6] * 0x1000000000000) + (chars[7] * 0x100000000000000);
}

void IntToChars(int64_t i, uint8_t* chars) {
    for(int k = 0; k < 8; k++) {
        chars[k] = i >> k*8;
    }
}

int main() {

    int64_t x;

    unsigned char chars[8];

    IntToChars(x, chars);

    for (int k = 0; k < 8; k++) {
        printf("%0x\n", chars[k]);
    }

    // little endian
    int64_t rv = CharsToInt(chars);

    printf("%lld\n", rv);
}

如果 x 是 12,或任何其他零或正数,代码可以正常工作,但如果 x 是负数,则无法工作。

x = 12 的输出:

c
0
0
0
0
0
0
0
value: 12

x 的输出 = -12:

f4
ff
ff
ff
ff
ff
ff
ff
value: -4294967308

这似乎与符号的存储和转换方式有关,因为我认为英特尔(我在 Mac 上)使用 2s-compliment 而不是普通的旧符号位。但是,我真的不知道如何确定这是否属实,如果是,如何弥补它(最好以便携的方式)。

我知道还有很多其他类似的问题,并且我已经阅读了它们(实际上大部分代码都来自它们),但我仍然无法让它工作,所以我问了我的拥有。

【问题讨论】:

  • 那么你对 -12 的期望是什么?
  • 为什么你认为FFFFFFFFFFFFFFF4-12 是错误的?
  • "...普通的旧符号位。"嗯,我很确定存储符号的电子不会比 2s 补码的电子老。两者实际上都用于现代计算机系统,以及第三种表示形式:偏置整数:大多数整数架构的 2s 补码,浮点尾数的单位和浮点指数的偏置(至少对于大多数现代 CPU 使用的 IEEE754 浮点数)。

标签: c arrays hex endianness


【解决方案1】:

在搞砸了一些之后,这就是我终于开始工作的地方(我想)。它实际上避免了必须同时处理字节顺序和 2s-compliment,通过删除符号并在转换后重新应用它,使用 C 掩码和乘法:

int64_t CharsToInt(uint8_t* chars) {
    // Don't modify argument
    uint8_t tmp;
    tmp = chars[0];
    bool neg = false;
    if (tmp & 0x80) {
        tmp &= 0x7f;
        neg = true;
    }

    int64_t rv = chars[7] + (chars[6] * 0x100) + (chars[5] * 0x10000) + (chars[4] * 0x1000000) + (chars[3] * 0x100000000) + (chars[2] * 0x10000000000) + (chars[1] * 0x1000000000000) + (tmp * 0x100000000000000);

    if (neg) {
        rv *= -1;
    }
    return rv;

}

void IntToChars(int64_t i, uint8_t* chars) {
    int64_t num = i;
    bool neg = false;
    if (i & 0x8000000000000000) {
        neg = true;
        num *= -1;
    }

    chars[0] = num / 0x100000000000000;
    num = num % 0x100000000000000;
    chars[1] = num / 0x1000000000000;
    num = num % 0x1000000000000;
    chars[2] = num / 0x10000000000;
    num = num % 0x10000000000;
    chars[3] = num / 0x100000000;
    num = num % 0x100000000;
    chars[4] = num / 0x1000000;
    num = num % 0x1000000;
    chars[5] = num / 0x10000;
    num = num % 0x10000;
    chars[6] = num / 0x100;
    num = num % 0x100;
    chars[7] = num;

    if (neg) {
        chars[0] += 0x80;
    }
}

【讨论】:

    【解决方案2】:

    你是对的。 Intel 64 和 IA-32 使用 2 补码表示有符号数。请参阅Intel 64 and IA-32 Architectures Software Developer’s Manual 第 4.2.1 节。因此,为 -12 读取 FFFFFFFFFFFFFFF4 是正确的。在 2 补码表示中,负数通过取对应的正数、反转所有位并加 1 来表示:

    12 = 000000000000000C -> FFFFFFFFFFFFFFF3 -> FFFFFFFFFFFFFFF4 = -12
    

    如果我可以添加一些东西,您也可以通过以下方式将您的 char 数组转换为 uint64_t

    int64_t CharsToInt(uint8_t* chars) {
        return *(int64_t*)chars;
    }
    

    【讨论】:

    • 我不认为我可以使用演员表,因为只有当角色以与平台相同的字节序排列时才会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2013-10-12
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 2021-11-18
    相关资源
    最近更新 更多