将 uint16_t 转换为十进制并将其按位存储在 char 数组中。检索 uint16_t 变量中的数据时出错

标签 c bit-manipulation bit pack unpack

int main()  
{  
    unsigned char ptr[9];  
    uint16_t dat = 128, s;  
    int i, j = 1, k;  

    ptr[0] = ptr[0] & 0;  
    j = -1;  

    for(i = 0;i <= 15;i++)  
    {  
        if(i % 8 == 0)
            j++;

        s = dat << i;  

        if (s & (1 << 15))  
            ptr[j] |= 1 << (7 - i%8);  
        else  
            ptr[j] |= 0 << (7 - i%8);  
    }  

    j = -1;  
    s &= 0;  

    for(i = 0;i <= 15;i++)  
    {         
        if(i % 8 == 0)  
            j++;  
        s |= (ptr[j] & (1 << (7 - i%8))) << (15 - i);  // <-----------  
        s |= (ptr[j] & (1 << i%8)) << (15 - i); // Correction
    }

    printf("%d", s);  

    return(0);
}

我试图将一个 16 字节整数打包到字符数组中,首先将其转换为二进制,然后将其逐位复制到数组中。但是,我在标记线方面遇到了麻烦。我得到 16834 作为输出。我在这里做错了什么?

最佳答案

如所写,输出是不确定的,因为您从未设置 ptr[1]到一个已知值。在我的 Mac 上,代码的这个微小变化(主要添加了一些标题、空格和 printf() 语句):

#include <stdint.h>
#include <stdio.h>

int main(void)
{
    unsigned char ptr[9];
    uint16_t dat = 128, s;
    int i, j = 1;

    ptr[0] = ptr[0] & 0;
    j = -1;
    printf("0x%.2X 0x%.2X\n", ptr[0], ptr[1]);

    for (i = 0; i <= 15; i++)
    {
        if (i % 8 == 0)
            j++;

        s = dat << i;

        if (s & (1 << 15))
            ptr[j] |= 1 << (7 - i % 8);
        else
            ptr[j] |= 0 << (7 - i % 8);
    }
    printf("0x%.2X 0x%.2X\n", ptr[0], ptr[1]);

    j = -1;
    s &= 0;

    for (i = 0; i <= 15; i++)
    {
        if (i % 8 == 0)
            j++;
        s |= (ptr[j] & (1 << (7 - i % 8))) << (15 - i);  // <-----------
    }

    printf("0x%.2X\n", s);
    printf("%d\n", s);

    return(0);
}

显示输出:

0x00 0xF4
0x00 0xF4
0x5510
21776

修改为替换 ptr[0] = ptr[0] & 0; 时与 ptr[0] = ptr[1] = 0; ,输出为:

0x00 0x00
0x00 0x80
0x4000
16384

你很不幸,你的机器将堆栈清零了;您将更难发现诸如未初始化变量之类的错误。

你选择128作为测试值让生活变得困难;仅设置了一位。如果我进行测试,我会使用一种独特的模式,例如 0x3CA5(C++14 二进制表示法中的 0b0011'1100'1010'0101)。当我更改代码以使用 0x3CA5 时,我得到输出:

0x00 0x00
0x3C 0xA5
0x5411
21521

好消息:第一个循环复制这些位,以便数字的高位字节位于 ptr[0] 中。低位字节在 ptr[1] 。坏消息:第二个循环似乎严重破坏了事情。

这是第二个循环的检测版本:

    for (i = 0; i < 16; i++)
    {
        if (i % 8 == 0)
            j++;
        uint16_t s0 = s;
        s |= (ptr[j] & (1 << (7 - i % 8))) << (15 - i);  // <-----------
        printf("i: %2d, j: %d, 7-i%%8: %d, ptr[j]: 0x%.2X, &val: 0x%.2X, "
               "|val = 0x%.5X, s0: 0x%.4X, s: 0x%.4X\n",
               i, j, 7 - i % 8, ptr[j], (1 << (7 - i % 8)),
               (ptr[j] & (1 << (7 - i % 8))) << (15 - i),
               s0, s);
    }

输出为:

0x00 0x00
0x3C 0xA5
i:  0, j: 0, 7-i%8: 7, ptr[j]: 0x3C, &val: 0x80, |val = 0x00000, s0: 0x0000, s: 0x0000
i:  1, j: 0, 7-i%8: 6, ptr[j]: 0x3C, &val: 0x40, |val = 0x00000, s0: 0x0000, s: 0x0000
i:  2, j: 0, 7-i%8: 5, ptr[j]: 0x3C, &val: 0x20, |val = 0x40000, s0: 0x0000, s: 0x0000
i:  3, j: 0, 7-i%8: 4, ptr[j]: 0x3C, &val: 0x10, |val = 0x10000, s0: 0x0000, s: 0x0000
i:  4, j: 0, 7-i%8: 3, ptr[j]: 0x3C, &val: 0x08, |val = 0x04000, s0: 0x0000, s: 0x4000
i:  5, j: 0, 7-i%8: 2, ptr[j]: 0x3C, &val: 0x04, |val = 0x01000, s0: 0x4000, s: 0x5000
i:  6, j: 0, 7-i%8: 1, ptr[j]: 0x3C, &val: 0x02, |val = 0x00000, s0: 0x5000, s: 0x5000
i:  7, j: 0, 7-i%8: 0, ptr[j]: 0x3C, &val: 0x01, |val = 0x00000, s0: 0x5000, s: 0x5000
i:  8, j: 1, 7-i%8: 7, ptr[j]: 0xA5, &val: 0x80, |val = 0x04000, s0: 0x5000, s: 0x5000
i:  9, j: 1, 7-i%8: 6, ptr[j]: 0xA5, &val: 0x40, |val = 0x00000, s0: 0x5000, s: 0x5000
i: 10, j: 1, 7-i%8: 5, ptr[j]: 0xA5, &val: 0x20, |val = 0x00400, s0: 0x5000, s: 0x5400
i: 11, j: 1, 7-i%8: 4, ptr[j]: 0xA5, &val: 0x10, |val = 0x00000, s0: 0x5400, s: 0x5400
i: 12, j: 1, 7-i%8: 3, ptr[j]: 0xA5, &val: 0x08, |val = 0x00000, s0: 0x5400, s: 0x5400
i: 13, j: 1, 7-i%8: 2, ptr[j]: 0xA5, &val: 0x04, |val = 0x00010, s0: 0x5400, s: 0x5410
i: 14, j: 1, 7-i%8: 1, ptr[j]: 0xA5, &val: 0x02, |val = 0x00000, s0: 0x5410, s: 0x5410
i: 15, j: 1, 7-i%8: 0, ptr[j]: 0xA5, &val: 0x01, |val = 0x00001, s0: 0x5410, s: 0x5411
0x5411
21521

除了 s0 中的值和s不是你想要的,忽略|val ,这些值就是我们所期望的;基本的迭代结构处于控制之中。然而,|val列显示存在问题 - 意外需要在输出格式中使用 5 个十六进制数字! i - 15移位并没有将位放置在您想要和需要放置的位置。

从这里开始,您需要自己解决问题。我希望这能为您提供一些关于如何调试此类问题的见解。

顺便说一句,问题已更新为提供:

s |= (ptr[j] & (1 << i%8)) << (15 - i); // Correction

在我的测试工具中,dat 中以 0x3CA5 作为初始值,产生输出:

0x00 0x00
0x3C 0xA5
i:  0, j: 0, 7-i%8: 7, ptr[j]: 0x3C, &val: 0x80, |val = 0x00000, s0: 0x0000, s: 0x0000
i:  1, j: 0, 7-i%8: 6, ptr[j]: 0x3C, &val: 0x40, |val = 0x00000, s0: 0x0000, s: 0x0000
i:  2, j: 0, 7-i%8: 5, ptr[j]: 0x3C, &val: 0x20, |val = 0x08000, s0: 0x0000, s: 0x8000
i:  3, j: 0, 7-i%8: 4, ptr[j]: 0x3C, &val: 0x10, |val = 0x08000, s0: 0x8000, s: 0x8000
i:  4, j: 0, 7-i%8: 3, ptr[j]: 0x3C, &val: 0x08, |val = 0x08000, s0: 0x8000, s: 0x8000
i:  5, j: 0, 7-i%8: 2, ptr[j]: 0x3C, &val: 0x04, |val = 0x08000, s0: 0x8000, s: 0x8000
i:  6, j: 0, 7-i%8: 1, ptr[j]: 0x3C, &val: 0x02, |val = 0x00000, s0: 0x8000, s: 0x8000
i:  7, j: 0, 7-i%8: 0, ptr[j]: 0x3C, &val: 0x01, |val = 0x00000, s0: 0x8000, s: 0x8000
i:  8, j: 1, 7-i%8: 7, ptr[j]: 0xA5, &val: 0x80, |val = 0x00080, s0: 0x8000, s: 0x8080
i:  9, j: 1, 7-i%8: 6, ptr[j]: 0xA5, &val: 0x40, |val = 0x00000, s0: 0x8080, s: 0x8080
i: 10, j: 1, 7-i%8: 5, ptr[j]: 0xA5, &val: 0x20, |val = 0x00080, s0: 0x8080, s: 0x8080
i: 11, j: 1, 7-i%8: 4, ptr[j]: 0xA5, &val: 0x10, |val = 0x00000, s0: 0x8080, s: 0x8080
i: 12, j: 1, 7-i%8: 3, ptr[j]: 0xA5, &val: 0x08, |val = 0x00000, s0: 0x8080, s: 0x8080
i: 13, j: 1, 7-i%8: 2, ptr[j]: 0xA5, &val: 0x04, |val = 0x00080, s0: 0x8080, s: 0x8080
i: 14, j: 1, 7-i%8: 1, ptr[j]: 0xA5, &val: 0x02, |val = 0x00000, s0: 0x8080, s: 0x8080
i: 15, j: 1, 7-i%8: 0, ptr[j]: 0xA5, &val: 0x01, |val = 0x00080, s0: 0x8080, s: 0x8080
0x8080
32896

这不是完整的答案。

I am trying to get the value of dat into s. I need it because I have to send the char array over a UDP socket. So at one end I will store integer as binary in a character array and then on the other end reassemble it as an integer.

您不需要进行按位运算即可获得您想要的结果;字节操作工作正常。

ptr[0] = dat >> 8;
ptr[1] = dat & 0xFF;  // You could get away without the '& 0xFF'

// Transmit over UDP

dat = (ptr[0] << 8) | ptr[1];

使用 unsigned char 很重要(你正在做的事情);如果您使用普通 char (或者,更糟糕的是 signed char ),那么你就必须担心符号位和符号扩展。

作为位操作的练习,这是有一定目的的;值得您花一些时间来修复代码以使其正常工作。作为一种操纵数据通过网络传输的方法,它不是一种好的工作方式,一旦您了解了有关位操作的知识,就应该放弃它。

解决问题的一种方法 - 不一定是最好的,无论我的努力如何 想象力,但一个有效的方法是修复 lhs << (15 - i) 的 LHS 移位,使其移位为 0 或 1。例如:

((ptr[j] & (1 << (7 - i % 8))) ? 1 : 0) << (15 - i)

关于将 uint16_t 转换为十进制并将其按位存储在 char 数组中。检索 uint16_t 变量中的数据时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26943628/

相关文章:

python - 在 python 中将各个位写入文件

c - ANTLR4 C 语法不支持 __cdecl?

在控制台中看不到 Windows 程序的标准输出(在 Windows 上用 Clang 编译)

c - 按位运算实现逻辑右移

c++ - 交换整数的第 i 位和第 j 位

c - 如何确保两个地址的最低有效 4 位相同?

c - 在 C 中跟随符号链接(symbolic link)

c - 删除二叉树中的一个叶节点

assembly - 使用按位运算将 Int 转换为 Float 或 Float 为 Int(软件浮点)

python - 计算 32 位整数列表中的非零位