C语言中如何将一个Int分成两个Byte?

Cur*_*ous 3 c io ansi-c

我正在使用嵌入在最小硬件中的软件,该软件仅支持 ANSI C 并且具有最小版本的标准 IO 库。

我有一个 Int 变量,大小为两个字节,但是我需要将它分开为 2 个字节才能传输它,然后我可以读取这两个字节,重新组合原始的 Int。

我可以想到每个字节的一些二进制划分,如下所示:

int valor = 522;  // 0000 0010 0000 1010 (entero de 2 bytes)
byte superior = byteSuperior(valor);  // 0000 0010
byte inferior = byteInferioror(valor);  // 0000 1010
...
int valorRestaurado = bytesToInteger(superior, inferior); // 522
Run Code Online (Sandbox Code Playgroud)

但我并没有成功地以一种简单的方式将整体除以它的重量,它给我一种感觉,它应该是微不足道的(例如位移位),而我没有发现它。

实际上,任何将整体分成 2 个字节并重新组装的解决方案都对我很有帮助。

从已经非常感谢你了!

小智 7

这不是一个“简单”的任务。

首先,C 中字节char的数据类型是。您可能需要unsigned char这里,因为char可以是签名的或未签名的,它是实现定义的。

int是一个有符号类型,这使得它的右移也由实现定义。就 C 而言,int必须至少有16 位(如果有 8 位则为 2 个字节char),但可以有更多。但当你的问题被写出来时,你已经知道int你的平台上有 16 位。在您的实现中使用这些知识意味着您的代码特定于该平台并且不可移植。

在我看来,你有两个选择:

  1. 您可以研究int使用掩码和位移位的价值,例如:

    int foo = 42;
    unsigned char lsb = (unsigned)foo & 0xff; // mask the lower 8 bits
    unsigned char msb = (unsigned)foo >> 8;   // shift the higher 8 bits
    
    Run Code Online (Sandbox Code Playgroud)

    int这样做的优点是您独立于内存中的布局。对于重建,请执行以下操作:

    int rec = (int)(((unsigned)msb << 8) | lsb );
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,强制转换msbunsigned此处是必要的,否则,它将被提升为int(int可以表示 an 的所有值unsigned char),当移位 8 位时可能会溢出。正如您已经说过的,您int有“两个字节”,这在您的情况下很可能是这样。

    最终的强制转换int也是实现定义的int,但如果编译器不做一些“奇怪”的事情,那么它将在 2 的补码中的16 位的“典型”平台上工作。通过首先检查unsigneda 是否太大int(因为原始int值为负),您可以避免这种情况,例如

    unsigned tmp = ((unsigned)msb << 8 ) | lsb;
    int rec;
    if (tmp > INT_MAX)
    {
        tmp = ~tmp + 1; // 2's complement
        if (tmp > INT_MAX)
        {
            // only possible when implementation uses 2's complement
            // representation, and then only for INT_MIN
            rec = INT_MIN;
        }
        else
        {
            rec = tmp;
            rec = -rec;
        }
    }
    else
    {
        rec = tmp;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    2 的补码在这里很好,因为C 标准中明确规定了将负数转换int为的规则。unsigned

  2. 您可以使用内存中的表示形式,例如:

    int foo = 42;
    unsigned char *rep = (unsigned char *)&foo;
    unsigned char first = rep[0];
    unsigned char second = rep[1];
    
    Run Code Online (Sandbox Code Playgroud)

    但请注意,firstMSB 还是 LSB 取决于您计算机上使用的字节顺序。另外,如果int包含填充位(实际上极不可能,但 C 标准允许),您也会读取它们。对于重建,请执行以下操作:

    int rec;
    unsigned char *recrep = (unsigned char *)&rec;
    recrep[0] = first;
    recrep[1] = second;
    
    Run Code Online (Sandbox Code Playgroud)

  • 我相信这是迄今为止最完整的答案,因此任何投反对票的人可能都想解释他们的疑虑...... (2认同)