Ann*_*inn 5 c++ optimization strict-aliasing language-lawyer bit-fields
我正在优化一种压缩算法,该算法使用跨 2 个字节的结构。但有时我希望它只解释 1 个字节,因为(我希望)映射到第二个字节的成员永远不会被写入或读取。
我是否能保证编译器不会访问第二个字节,只要 和zFmt永远wFmt不会被访问?如果不是,我可以编写一个静态断言,当这个假设错误时将停止编译吗?
struct Header {
uint8_t xFmt : 4;
uint8_t yFmt : 4;
uint8_t zFmt : 4; // must not be read/written when header is mapped to 1 byte
uint8_t wFmt : 4; // must not be read/written when header is mapped to 1 byte
};
static_assert( sizeof(Header) == 2 && alignof(Header) == 1, "alignment vital");
// --- usage ---
int main(){
// Header may be placed into memory where it overlaps only one byte;
// in that case, it's .zFmt and .wFmt members are never read or written to
char buffer[1];
Header * header = new (buffer) Header;
// can I be sure (or statically assert) that these instructions
// will only read and write to the nearest (and only) owned byte?
header->xFmt = 0;
header->yFmt = 0;
header->xFmt += 1;
header->yFmt += 1;
}
Run Code Online (Sandbox Code Playgroud)
旁注:
该算法目前有效,但我想确保它不依赖于未定义的行为。我相信通过使用新的放置来遵守严格别名,但也许这个假设是不正确的?
另外,我想以这种方式使用这个结构和位字段......因为它们看起来不错!不是最好的原因哈哈,所以如果这是不可能的,我的后备方法是解释没有结构的字节,就像uint8_t移位和掩码一样。我还知道我可以使用继承来执行切片,如果这是未定义的,我将研究它。
回答我自己的问题,因为我相信我已经在 2020 版 C++ ISO 标准中找到了答案(将相关部分加粗):
\n\n\n\n
\n- 内存位置可以是标量类型的对象,也可以是具有非零宽度的相邻位字段的最大序列。[注意:语言的各种功能,例如引用和虚拟函数,可能涉及\n程序无法访问但由实现管理的其他内存位置。\n\xe2\x80\x94 尾注] 两个或多个线程执行(6.9.2)可以访问单独的内存位置,而不会互相干扰。
\n
\n\n\n
\n- [注意:因此,位字段和相邻的非位字段位于不同的内存位置,因此可以由两个执行线程同时更新而不会产生干扰。这同样适用于两个位域,\n如果一个位域是在嵌套结构声明内声明的,而另一个不是,或者如果这两个位域由零长度位域声明分隔,或者如果它们由非-位域声明。如果同一结构中的两个位域之间的所有域都是非零宽度的位域,那么同时更新这两个位域是不安全的。\xe2\x80\x94 尾注]
\n
struct {\n char a;\n int b:5,\n c:11,\n :0,\n d:8;\n struct {int ee:8;} e;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n
\n- [示例:声明为[上述]的类包含四个单独的内存位置:成员 a 以及位字段 d 和 e.ee 都是单独的内存位置,并且可以同时修改而不会相互干扰。位字段 b 和 c\n 一起构成第四个存储位置。位字段 b 和 c 不能同时修改,但例如 b 和 a 可以。\xe2\x80\x94结束示例]
\n
关于“两个或多个执行线程”访问单独的内存位置的注释使我相信以下内容:
\nyFmt不会导致明显的副作用。正如 Nate 的评论所指出的,编译后的代码仍然可以加载并存储到它认为zFmt存在的位置,同时满足此要求。但是,如果访问必须是原子的并保留先前的值(只要程序拥有此内存),那么就只有一种可能的行为。(至于拥有内存的程序,只要原子指令在比程序可以拥有内存更精细地对齐的内存上工作,我相信情况就是如此,那么我很舒服地假设我不会导致访问冲突这边走。)除了结构的所有成员和位字段必须具有递增地址的规则之外,我相信这使我的用法得到了明确的定义,并进行了以下更改:
\nstruct Header {\n uint8_t xFmt : 4;\n uint8_t yFmt : 4;\n uint8_t :0;\n uint8_t zFmt : 4; // must not be read/written when header is mapped to 1 byte\n uint8_t wFmt : 4; // must not be read/written when header is mapped to 1 byte\n};\n\nstatic_assert( sizeof(Header) == 2 && alignof(Header) == 1, "");\nRun Code Online (Sandbox Code Playgroud)\n当然,并不是说它不容易导致程序员错误,但我相当确信这是明确定义的,至少目前是这样。
\n| 归档时间: |
|
| 查看次数: |
150 次 |
| 最近记录: |