我正在为二进制协议(Javad GRIL协议)编写解码器.它由大约一百条消息组成,数据格式如下:
struct MsgData {
uint8_t num;
float x, y, z;
uint8_t elevation;
...
};
Run Code Online (Sandbox Code Playgroud)
这些字段是ANSI编码的二进制数,它们彼此之间没有间隙.解析此类消息的最简单方法是将输入的字节数组转换为适当的类型.问题是流中的数据是打包的,即未对齐的.
在x86上,这可以通过使用来解决#pragma pack(1).但是,这在某些其他平台上不起作用,或者由于未对齐数据而导致性能开销.
另一种方法是为每种消息类型编写一个特定的解析函数,但正如我所提到的,该协议包含数百条消息.
另一种选择是使用类似Perl unpack()函数的东西并在某处存储消息格式.说,我们可以#define MsgDataFormat "CfffC"再打电话unpack(pMsgBody, MsgDataFormat).这要短得多,但仍然容易出错并且多余.此外,格式可能更复杂,因为消息可以包含数组,因此解析器将是缓慢而复杂的.
有没有共同有效的解决方案?我已经阅读了这篇文章,并用Google搜索,但没有找到更好的方法来做到这一点.
也许C++有一个解决方案?
我有一个数组,用作类型对象的底层内存T:
char memory[sizeof T];
.
.
.
new(memory) T(whatever);
Run Code Online (Sandbox Code Playgroud)
如何确保对象memory正确对齐T?在C++ 0x中我可以说:
alignas(T) char memory[sizeof T];
Run Code Online (Sandbox Code Playgroud)
但Visual Studio 2010尚不支持该特定功能.
我有一个配置结构我想保存在ARM cortex M3的内部闪存上.根据规格,数据保存在内部闪存中,必须与32bit对齐.因为我有很多boolean和chars在我的结构中,我不想使用32位存储8位...我决定使用__packed预处理器编译指示打包结构,然后当我将它保存为整个结构时,我只需要确保结构大小可被4整除(4个字节= 32位),如果需要,我可以通过添加填充字节来实现.目前,在开发过程中我经常更改结构,并使其与32位对齐,我需要一直更改填充字节.目前,结构看起来很像
typedef __packed struct
{
uint8_t status;
uint16_t delay;
uint32_t blabla;
uint8_t foo[5];
uint8_t padding[...] // this has to be changed every time I alter the structure.
} CONFIG;
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来实现我正在做的事情?我是嵌入式编程的新手,我想确保我没有犯错误.
编辑:请注意.数据在内部闪存结束时保留,因此省略填充将无法正常工作......
今天我通过追踪一个非常规避的腐败漏洞遇到了很多麻烦.
我想如果我真的注意到这些警告就不会那么难找到,但由于我没有找到有关为什么会弹出这个特定警告的相关信息,我让它滑动,这是一个错误.
所以这是Visual Studio 2013给我的有罪警告:
warning C4316: object allocated on the heap may not be aligned 16
Run Code Online (Sandbox Code Playgroud)
当通过const引用将align(16)临时传递给构造函数时生成它,如下面的代码所示:
class Vector
{};
__declspec(align(16)) class VectorA
{};
class Shape
{
public:
Shape(const Vector& vec) {}
};
class ShapeA
{
public:
ShapeA(const VectorA& vec) : mVec(vec) {}
private:
VectorA mVec;
};
int main(int argc, char *argv[])
{
Shape* shape = new Shape(Vector()); // ok
ShapeA* shapea = new ShapeA(VectorA()); // warning C4316:
// object allocated on the heap may not be aligned 16 …Run Code Online (Sandbox Code Playgroud) 我试图理解未对齐的内存访问(UMA)如何在现代处理器(即x86-64和ARM体系结构)上工作.我知道我可能遇到UMA问题,从性能下降到CPU故障.我阅读posix_memalign并缓存行.
我找不到的是当我的请求超出页面边界时,现代系统/硬件如何处理这种情况?
这是一个例子:
malloc()是一块8KB的内存.malloc()没有足够的内存和sbrk()8KB的话.movq (offset + $0xffc), %rax 我从第4092字节开始请求8个字节,这意味着我需要从第一页末尾开始的4个字节和从第二页开始开始的4个字节.物理内存:
---|---------------|---------------|-->
|... 4b| | |4b ...|-->
Run Code Online (Sandbox Code Playgroud)
我需要在页面边界分割的8个字节.
x86-64和ARM上的MMU如何处理这个问题?内核MM中是否有任何机制以某种方式为这种请求做准备?是否有某种保护malloc?处理器做什么?他们取两页吗?
我的意思是完成这样的请求MMU必须将一个虚拟地址转换为两个物理地址.它如何处理这样的请求?
如果我是软件程序员,我应该关心这些事情吗?为什么?
我正在阅读谷歌,SO,drepper的cpumemory.pdf和gorman的Linux VMM书中的很多链接.但它是一个信息的海洋.如果您至少向我提供一些我可以使用的指针或关键字,那将会很棒.
我遵循 Stefanus Du Toit 的沙漏模式,即在 C++ 中实现 C API,然后再次将其包装在 C++ 中。这与pimpl idiom非常相似,它对用户也是透明的,但可以防止更多与 ABI 相关的问题并允许更广泛的外语绑定。
与实现指针的方法一样,底层对象的大小和布局在编译时不被外界所知,因此它所在的内存必须动态分配(主要是)。然而,与pimpl情况不同,在pimpl情况下,对象已在分配点完全定义,这里它的属性完全隐藏在不透明指针后面。
获得的内存std::malloc是“适合任何标量类型”,这使得它不适合任务。我不确定new-expression。引自链接页面的分配部分:
此外,如果 new 表达式用于分配一个 char 数组或一个 unsigned char 数组,它可能会在必要时从分配函数中请求额外的内存,以保证不大于请求的数组大小的所有类型的对象的正确对齐,如果稍后将一个放入分配的数组中。
这是否意味着以下代码是合规的?
size_t object_size ( void ); // return sizeof(internal_object);
size_t object_alignment ( void ); // return alignof(internal_object);
void object_construct ( void * p ); // new (p) internal_object();
void object_destruct ( void * p ); // …Run Code Online (Sandbox Code Playgroud) 以下显然有效的代码使用UndefinedBehaviorSanitizer sanitiser产生错位的地址运行时错误.
#include <memory>
#include <functional>
struct A{
std::function<void()> data; // seems to occur only if data is a std::function
} ;
struct B{
char data; // occurs only if B contains a member variable
};
struct C:public virtual A,public B{
};
struct D:public virtual C{
};
void test(){
std::make_shared<D>();
}
int main(){
test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在macbook上编译和执行
clang++ -fsanitize=undefined --std=c++11 ./test.cpp && ./a.out
产生输出
runtime error: constructor call on misaligned address 0x7fe584500028 for type 'C', which requires 16 byte …
是sizeof(Type)始终整除alignof(Type)
这样的陈述永远是真的吗? sizeof(Type) % alignof(Type) == 0
最近,我意识到的潜在问题内存对齐为固定大小的矢量化的本征对象。
class Foo
{
...
Eigen::Vector2d v;
...
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
...
Foo *foo = new Foo;
Run Code Online (Sandbox Code Playgroud)
我想知道这个代码是否可以?
class Foo2
{
...
Foo foo;
...
};
...
Foo2 *foo = new Foo2; //?
Run Code Online (Sandbox Code Playgroud)
还是应该EIGEN_MAKE_ALIGNED_OPERATOR_NEW在Foo2类中再次添加?这就是建议在这里我想:
如果我们添加 EIGEN_MAKE_ALIGNED_OPERATOR_NEW,这只能解决 Cartographer 库本身的问题。该库的用户还必须将 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 添加到包含矢量化 Cartographer 类的类中。这听起来像是一场维护噩梦。
我没有新运算符重载的经验。我认为这个问题更笼统,并且以某种方式与 new 运算符在 C++ 中的工作方式有关。例如,重载的 new 运算符 inFoo是否被默认的 new 运算符 in 调用Foo2?继承呢?如果Foo2从继承Foo,要我们把同样EIGEN_MAKE_ALIGNED_OPERATOR_NEW的Foo2? …
我不习惯在互联网上发布任何问题,所以如果我做错了什么,请告诉我。
如何在 CPU 缓存行大小为 64 字节的 64 位架构上正确防止错误共享?
C++ 'alignas' 关键字和简单字节数组(例如:char[64])的使用如何影响多线程效率?
在研究Single Consumer Single Producer Queue的非常有效的实现时,我在对我的代码进行基准测试时遇到了 GCC 编译器的不合逻辑行为。
我希望有人有必要的知识来解释正在发生的事情。
我目前在 arch linux 上使用 GCC 10.2.0 及其 C++ 20 实现。我的笔记本电脑是带有 i7-7500U 处理器的联想 T470S。
让我从数据结构开始:
class SPSCQueue
{
public:
...
private:
alignas(64) std::atomic<size_t> _tail { 0 }; // Tail accessed by both producer and consumer
Buffer _buffer {}; // Buffer cache for the producer, equivalent to _buffer2
std::size_t _headCache { 0 }; // Head cache for the …Run Code Online (Sandbox Code Playgroud)