2016-11-23 35 views
2

我想分配一些内存,将其初始化为一些值,然后将此内存的不同部分转换为不同的结构。东西如下:将内存投射到工会

union structA{ 
    __int8 mem[3]; 

    struct{ 
    unsigned field1 : 8; 
    unsigned field2 : 12; 
    unsigned field3 : 4; 
    }; 
}; 

struct structB{ 
    __int8 mem[10]; 
}; 


__int8 globalMem[128]; 

structA a1 <---- &globalMem[0] 
structA a2 <---- &globalMem[10] 
structB b1 <---- &globalMem[30] 

我尝试使用reinterpret_cast的,我没有得到任何编译器错误,但似乎我的变量(a1a2b1)并没有真正分配/正确初始化。

任何有关为什么这不起作用的想法和什么是实现这样的事情的正确方法?

谢谢!

+4

位域对齐和填充是实现定义的。您将需要调查您的编译器是否在位域中添加了填充到结构中。极有可能。 –

+0

也使用一个签名的基础类型('__int8')可能不是最好的主意。 –

+1

试图用 '编译包(推,1) 编程 编译包(弹出)' 它应该消除任何填充问题,如山姆Varshavchik提到的。 – GoldenSpecOps

回答

0

要达到什么样的,你打算做需要使用reinterpret_cast的:

structA a1 = *reinterpret_cast<structA*>(&globalMem[0]); 
structA a2 = *reinterpret_cast<structA*>(&globalMem[10]); 
structB b1 = *reinterpret_cast<structB*>(&globalMem[30]); 

这有什么错呢?

这需要格外小心,因为C++ struct是一种特殊的class,而且这种分配的不尊重对象的语义(因为在不同globalMem地址的内容是不是正确的对象,除非你初始化” d在你的代码中使用placement new)。

在使用这种技巧之前,您还可以确保structA是可复制的(is_trivially_copyable<structA>::value,幸运的是这里是真的)。

此外,对齐约束可能存在问题,因为globalMem没有对齐约束,但根据编译器/体系结构的不同,structA可能需要字对齐。

最后,structA的大小不一定是3,因为你倾向于这样想。事实上在某些编译器将是4,如this online demo

其他的看法

你可以使用标准类型uint8_t,而不是编译器特定类型的名称以双下划线。

关于对齐和大小主题,我建议你对内存布局假设非常谨慎。我宁愿建议你的globalMem考虑将它作为它包含的所有结构的结构,以确保正确的对象语义并且具有安全的布局。

+0

但这只会将globalMem的一部分复制到a1等。它实际上不会将a1,a2和b1“映射”到globalMem的某些部分。 – Ali

+0

@Ali在你的布局中有几个问题(见编辑),这让我认为你的映射控制采取了错误的假设(从struct A的大小开始)。我邀请你看看这个在线演示:http://ideone.com/K3PYpT,你会发现prpeprly初始化的对象被正确复制,尽管重新解释转换。但是,重新解释演员通常会出现一个值得重新考虑的棘手设计。 – Christophe