【问题标题】:How do I concatenate integer binary values in an array in C?如何在 C 中连接数组中的整数二进制值?
【发布时间】:2018-10-28 09:54:28
【问题描述】:

我正在编写一个嵌入式系统程序,它通过 SPI 从外部 ADC 接收 24 位数据,并将数据存储在一个整数数组中。那部分正在工作。为了使数据有用,我需要以二进制或十六进制形式连接每个字节并除以 0x7FFFFFF。这就是我遇到麻烦的地方。例如,我可能会通过 SPI 收到一个如下所示的数据数组:

data_buffer = { 24 , 17 , 140 };

又名

data_buffer = { 0b00011000 , 0b00010001 , 0b10001100 };

又名

data_buffer = { 0x18 , 0x11 , 0x8C };

我需要对这个值做的是连接每个元素以获得如下内容:

data_value = 0x18118C

然后将该值除以 0x7FFFFF 以使其在我的程序中有用。在这个例子中,我想最终得到的值是 0x18118C/0x7FFFFF = 0.188

我该怎么做呢?

很抱歉我没有提供更多代码,我真的不知道从哪里开始。

【问题讨论】:

    标签: c binary embedded hex


    【解决方案1】:

    将三个字节组合成一个 24 位(实际上是 32 位)值是 C 位运算符的简单应用。 这是一个冗长的“速记”形式:

    unsigned char data_buffer[] = { 24 , 17 , 140 };
    
    unsigned long int data_value = 0;
    data_value |= data_buffer[0];
    data_value <<= 8;
    data_value |= data_buffer[1];
    data_value <<= 8;
    data_value |= data_buffer[2];
    

    我可能会把它写成更紧凑的形式:

    unsigned long int data_value = 0;
    data_value |= data_buffer[0];
    data_value = (data_value << 8) | data_buffer[1];
    data_value = (data_value << 8) | data_buffer[2];
    

    或者您可以按其他顺序执行,可以这么说:

    unsigned long int data_value = 0;
    data_value |= (unsigned long)data_buffer[0] << 16;
    data_value |= data_buffer[1] << 8;
    data_value |= data_buffer[2];
    

    (不过,如果您使用的是 16 位处理器,那么这里需要额外的演员表,而普通的 data_buffer[0] &lt;&lt; 16 会将所有位移开并丢失它们。)

    或者您可以一次完成所有操作:

    unsigned long int data_value =
        ((unsigned long)data_buffer[0] << 16) |
                       (data_buffer[1] << 8) |
                        data_buffer[2];
    

    在任何情况下,您都可以进行所需的除法:

    float float_value = (float)data_value / 0x7FFFFF;
    

    (您可能希望使用double 而不是float。或者根据您的嵌入式环境的限制,您可能根本不希望使用像这样简单的浮点;您没有说。)

    当我打印这些时,我会得到您要求的值:

    printf("data_value = %#lX, float_value = %f\n", data_value, float_value);
    

    产量:

    data_value = 0X18118C, float_value = 0.188036
    

    附录:我忘记提及的一件事是,要使这些技术正常工作,您的输入数据(即示例中的 data_buffer 数组)的类型通常非常重要 @ 987654332@。如果不是——例如,如果它是在大多数机器上签名的普通char——你通常最终会遇到令人衰弱的符号扩展问题。例如,您的值 140 是十六进制数 0x8c,如您所知,但解释为 有符号 8 位数字,即 -116。当它与其他整数一起参与表达式时,它通常会被符号扩展为0xff8c0xffffff8c,这当然不是你想要的。 (您可以使用额外的 &amp; 0xff 掩码解决此问题,正如 SteveB 的回答中所建议的那样,但这很麻烦。使用 unsigned char 更简单。)

    【讨论】:

    • 感谢史蒂夫的回复,它非常有帮助。数组的类型是 'static uint8_t' ,我在更改这种类型时没有太大的灵活性,因为我使用的是一些示例代码中的函数。这种类型也可以吗?
    • 是的,uint8_t 是无符号的,基本上等同于unsigned char,应该可以正常工作。
    【解决方案2】:

    最简单的方法是将值转换为正确大小的整数。在您的示例中:

    int data_value = 0;
    for (i = 0; i < 3; ++i) {
        data_value = data_value << 8;
        data_value |= data[i] & 0xff;    // Makes sure you are only adding 8 bits
    }
    

    您可以根据需要对不同的数组大小进行调整。您只需要确保 data_value 足够大以容纳所有内容。由于您使用的是 24 位数据,因此可以使用 32 位整数。然后您将 data_value 分配给浮点值并进行除法。

    double data_double = data_value;
    double final_value = data_double / 8388607.0
    

    您需要使用浮点值 0x7FFFFF 以避免整数截断。

    【讨论】:

    • 不知道目标上int的长度,使用int32_tuint32_t会更安全和合适。
    • @Clifford - OP 说他正在处理 24 位数据,他正在除以 32 位数字。知道这一点,该平台上的 int 至少为 32 位。如果不是,则无论如何都不会支持 int32_t 和 uint32_t。由于他使用的是 24 位数据,因此整数结果是否带符号无关紧要。我的解决方案可以正常工作。请在投反对票之前完整阅读问题和答案。
    • 但我们不知道 int 是 32 位,而 int 是 16 位并不排除 32 位类型的可用性。使用 stdint 类型避免了需要知道底层类型是需要是 int 还是 long int。我做梦也不会想到会否决这一点-只是建议改进。然而,你的评论是惊人的错误。是的,在这种情况下,有符号或无符号没有区别(假设它不是需要额外处理的 24 位 2 的补码)——这也是我建议的原因。
    • 道歉@Clifford。我以为你投了反对票,抱歉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    • 2020-12-11
    • 2017-08-22
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    相关资源
    最近更新 更多