【问题标题】:Decoding signed CAN bytes in C在 C 中解码带符号的 CAN 字节
【发布时间】:2022-11-27 04:26:48
【问题描述】:

我一直在尝试编写一个函数来解码 C 中的 CAN 字节,同时考虑到传入值的字节序和系统的字节序。现在,它适用于无符号值,但对有符号值很糟糕。

我有一种感觉,我深深地误解了 C 中签名表示的工作方式——我假设 MSB 是签名数据的符号标志(即 Little Endian 的最后一个字节,Big Endian 的第一个字节)。谁能看看我下面的功能,让我知道我做错了什么?

/**
 * @brief can_interact_decode - converts array of length x containing hex bytes into a uint64
 * @param[in] const uint8_t* - const array of hex bytes
 * @param[in] const size_t - length of hex bytes array
 * @param[in] const enum can_interact_signedness - whether the bytes are storing a signed value or not. SIGNED_VAL indicates signed, UNSIGNED_VAL indicates unsigned
 * @param[in] const enum can_interact_endianness - endianess. LITTLE_ENDIAN_VAL is little, BIG_ENDIAN_VAL is big
 * @return[out] uint64_t - interpreted value as unsigned int from hex bytes, taking other params into account
 */
uint64_t can_interact_decode(const uint8_t *payload, const size_t data_len, const enum can_interact_signedness is_signed, const enum can_interact_endianness byte_order)
{
    uint64_t result; /* [0,0,0,0,0,0,0,0] */
    uint8_t* blocks; /* array of 8 */
    result = 0;
    blocks = (uint8_t*)(&result);

    if(byte_order == LITTLE_ENDIAN_VAL) {
        memcpy(blocks, payload, (is_signed ? data_len - 1 : data_len));
        blocks[7] = is_signed ? payload[data_len - 1] : blocks[7];
        result = le64toh(result); /* little endian->host byte order */
    } else if(byte_order == BIG_ENDIAN_VAL) {
        memcpy(blocks + (8 - data_len) + (is_signed ? 1 : 0), (is_signed ? payload + 1 : payload), (is_signed ? data_len - 1 : data_len));
        blocks[0] = is_signed ? payload[0] : blocks[0];
        result = be64toh(result); /* big endian->host byte order */
    }

    return result;
}

【问题讨论】:

  • "Little Endian 的最后一个字节,Big Endian 的第一个字节" --> 符号少量, 不是字节, 是那些字节的一部分。
  • data_len 是否大于 8?还是小于 1?
  • 不,不是。我将添加 ifs 等检查此类内容。为其他功能编写一个库,实际上我已经把所有的东西都写在那里了,但此时只是想专注于基本功能 @chux-ReinstateMonica
  • 啊。我看到我的错误。如果你这么好心,你会如何提取最重要的少量从一个字节?我猜想与 << 或 >> 运营商有关? @chux-恢复莫妮卡
  • 你是说(int8_t) payload[data_len - 1] &lt; 0?

标签: c hex endianness can-bus


【解决方案1】:

问题:

标志延伸困境

OP 似乎想要签署 extend the sign少量进入其他字节.

if(byte_order == LITTLE_ENDIAN_VAL) {
    //memcpy(blocks, payload, (is_signed ? data_len - 1 : data_len));
    //blocks[7] = is_signed ? payload[data_len - 1] : blocks[7];
    memcpy(blocks, payload, data_len);
    if (is_signed && ((const int8_t*)payload)[data_len - 1] < 0) {
      memset(blocks + data_len, 0xFF, 8 - data_len);
    }  
    result = le64toh(result); /* little endian->host byte order */

我将在 else if(byte_order == BIG_ENDIAN_VAL) 块中留下类似的更改,供 OP 执行。

【讨论】:

  • 除了未初始化的数据注释(正如我在下面的两行中所做的那样),这一切看起来都很棒,我会试一试,谢谢!
  • @SalihMSA 提示:考虑var_type var = 0;,而不是var_type var; /* lines later */ var = 0;。这是更清晰的代码。
  • @SalihMSA payload[0] &lt; 0 始终为假,因为 payload[0] 为未签名.这暗示您没有在启用所有警告的情况下进行编译。省时间。启用它们。
  • 至少,我使用-迂腐的-Wall -Wextra -Wconversion.
  • 对于 BE,也许是memcpy(blocks + (8 - data_len), payload), data_len); if (is_signed &amp;&amp; ((const int8_t*)payload)[0] &lt; 0) { memset(blocks, 0xFF, 8 - data_len);?
猜你喜欢
  • 1970-01-01
  • 2013-07-19
  • 2013-07-02
  • 1970-01-01
  • 2017-04-19
  • 2021-02-18
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多