[英]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.