簡體   English   中英

位對齊任何位長字節對齊緩沖區的訪問權限

[英]Bit aligned Acess of any bit length byte aligned buffer

對於嵌入式系統(小Endian ARM,語言C-即使我將C ++用於測試目的),我編寫了所附的代碼。 我必須發送和接收不同的配置數據,這些數據按位對齊並具有給定的位長。 對於每個我必須發送/接收的變量,使用field_conf_t執行配置:

typedef struct field_conf_t { ... }; // see below

typedef struct {
    field_conf_t    a;
    field_conf_t    b;
    field_conf_t    c;
} tx_fields_conf_t;

const tx_fields_conf_t tx_fields_conf = {
    { 0, 8  },      // a - offset/length
    { 28, 12 },     // b - offset/length
    { 56, 8  }      // c - offset/length
};

我遇到的問題是,我對單個位操作大多認為測試失敗。

這里的代碼:

#include <stdint.h>

#define BOOST_TEST_MODULE BitFieldTest
#include <boost/test/unit_test.hpp>

typedef uint8_t     uint8;
typedef uint16_t    uint16;
typedef uint32_t    uint32;
typedef unsigned long long uint64;

typedef struct {
    uint8   offset;     // [0-63]
    uint8   length;     // [1-32]
} field_conf_t;

typedef struct {
    field_conf_t    a;
    field_conf_t    b;
    field_conf_t    c;
} tx_fields_conf_t;

typedef union {
    uint8   buf[8];
    uint64  contents;
} msg_t;

void set_value(msg_t* const msg, const field_conf_t* const field, uint32 value)
{
    const uint32 mask = (1 << field->length) - 1;
    msg->contents    &= ~(mask          << field->offset);  // clear old contens
    msg->contents    |=  (value & mask) << field->offset;   // set new contens
}

uint32 get_value(const msg_t* const msg, const field_conf_t* const field)
{
    const uint32 mask = (1 << field->length) - 1;

    uint64 value = (msg->contents >> field->offset);
    value       &= mask;

    return (uint32)value;
}

// ########################################################################
struct TestFixture {
    TestFixture() : a(0xAA), b(0xBBB), c(0xCC) {
        conf.a.offset =  0; conf.a.length = 8;
        conf.b.offset = 25; conf.b.length = 12;
        conf.c.offset = 56; conf.a.length = 8;
    }
    uint32 a, b, c;
    msg_t msg;
    tx_fields_conf_t conf;
};

BOOST_FIXTURE_TEST_SUITE(MsgBitfieldTest, TestFixture);

BOOST_AUTO_TEST_CASE(Test_01)
{
    set_value(&msg, &conf.a, a);
    BOOST_CHECK(get_value(&msg, &conf.a) == a);

    set_value(&msg, &conf.b, b);
    BOOST_CHECK(get_value(&msg, &conf.a) == a);
    BOOST_CHECK(get_value(&msg, &conf.b) == b);

    set_value(&msg, &conf.c, c);
    BOOST_CHECK(get_value(&msg, &conf.a) == a);
    BOOST_CHECK(get_value(&msg, &conf.b) == b);
    BOOST_CHECK(get_value(&msg, &conf.c) == c);
}

BOOST_AUTO_TEST_SUITE_END();

和測試運行輸出

Running 1 test case...
d:/work/bugee/test/can_msg/msg_bitsfields/msg_bitsfields/main.cpp(65): error in
"Test_01": check get_value(&msg, &conf.b) == b failed
d:/work/bugee/test/can_msg/msg_bitsfields/msg_bitsfields/main.cpp(69): error in
"Test_01": check get_value(&msg, &conf.b) == b failed
d:/work/bugee/test/can_msg/msg_bitsfields/msg_bitsfields/main.cpp(70): error in
"Test_01": check get_value(&msg, &conf.c) == c failed

*** 3 failures detected in test suite "BitFieldTest"

緩沖區大小始終為8個字節; 我很高興在這里可以使用64位長的代碼。 在我也無法進行字節對齊的操作之前(每個字節上的掩碼和位操作)。 請注意,該值不能超過INT32 / UINT32更大。 我也知道C位域。 它們太慢,我需要一個用於所用嵌入式系統的快速解決方案(那里還有其他耗時的任務)。

我也對采用lsb / msb 32位甚至8字節分片快速解決方案的解決方案感興趣,但是由於編譯器的原因,我認為使用64位數據類型的性能更高。

在第一個代碼塊中有以下事實是否有問題:

const tx_fields_conf_t tx_fields_conf = {
    { 0, 8  },      // a - offset/length
    { 28, 12 },     // b - offset/length -- note the 28 here as the offset
    { 56, 8  }      // c - offset/length
};

但是稍后在您的應用程序中,您可以:

struct TestFixture {
    TestFixture() : a(0xAA), b(0xBBB), c(0xCC) {
        conf.a.offset =  0; conf.a.length = 8;
        conf.b.offset = 25; conf.b.length = 12;  // offset is *25* here, not 28 as above. Poss. problem?
        conf.c.offset = 56; conf.a.length = 8;
    }
    uint32 a, b, c;
    msg_t msg;
    tx_fields_conf_t conf;
};

有什么重大差異的機會嗎? 也許什么也沒有,但是我確實注意到了……想指出來。

問題是在set_value

const uint32 mask = (1 << field->length) - 1;
msg->contents    &= ~(mask          << field->offset);  // clear old contens
msg->contents    |=  (value & mask) << field->offset;   // set new contens

mask << field->offset是一個32位值,因此當field->offset + field->length >= 32時,將從邊緣溢出。 mask更改為64位應該可以使移位作為64位操作執行:

const uint64 mask = (1 << field->length) - 1;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM