如何创建不会破坏严格混叠的uint8_t数组
How to create an uint8_t array that does not undermine strict aliasing?
我最近问了这个问题:
使用此指针会导致热循环中出现奇怪的去优化
问题是我正在写入一个 uint8_t
类型的数组,编译器将其视为可以使用方法(类型 struct T*
(的this
指针进行别名,因为void*
和char*
(= uint8_t*
(总是可以在C++中为任何其他指针别名。此行为导致错失优化机会。当然,我想避免这种情况。所以问题是:我是否可以声明一个强制严格混叠的uint8_t
数组,即编译器将其视为从不与其他类型的任何指针混叠?即,我正在寻找类似strict_uint8_t
类型的东西,它是一种具有特殊混叠行为的uint8_t
。有没有办法实现这一目标?
示例代码来显示我的意思,借用其他问题并简化。有关更多详细信息,请阅读链接的问题及其接受的答案:
struct T{
uint8_t* target;
void unpack3bit(char* source, int size) {
while(size > 0){
uint64_t t = *reinterpret_cast<uint64_t*>(source);
/** `this->target` cannot be cached in a register here but has
to be reloaded 16 times because the compiler
thinks that `this->target` could alias with `this` itself.
What I want is a special uint8_t type that does not trigger
this behaviour. */
this->target[0] = t & 0x7;
this->target[1] = (t >> 3) & 0x7;
this->target[2] = (t >> 6) & 0x7;
this->target[3] = (t >> 9) & 0x7;
this->target[4] = (t >> 12) & 0x7;
this->target[5] = (t >> 15) & 0x7;
this->target[6] = (t >> 18) & 0x7;
this->target[7] = (t >> 21) & 0x7;
this->target[8] = (t >> 24) & 0x7;
this->target[9] = (t >> 27) & 0x7;
this->target[10] = (t >> 30) & 0x7;
this->target[11] = (t >> 33) & 0x7;
this->target[12] = (t >> 36) & 0x7;
this->target[13] = (t >> 39) & 0x7;
this->target[14] = (t >> 42) & 0x7;
this->target[15] = (t >> 45) & 0x7;
source+=6;
size-=6;
target+=16;
}
}
};
可以使用基类型 uint8_t
的固定大小枚举:
enum strict_uint8_t : uint8_t {};
如果您希望能够以透明的方式与uint8_t
进行转换,则可以将其包装在带有转换构造函数和转换运算符的struct
中:
struct strict_uint8_t {
enum : uint8_t {} i;
strict_uint8_t(uint8_t i) : i{i} {}
operator uint8_t() const { return i; }
};
这似乎消除了 gcc 和 clang 中的混叠悲观化:https://godbolt.org/g/9Ta98b
(注意:以前的方法使用位域,在 gcc 中有效,但在 clang 中不起作用。
在Visual Studio中,你可以对函数使用__declspec(restict)
,对变量使用__restrict
来告诉编译器指针是无别名的。我相信在像GCC这样的其他编译器中,有一个__restrict__
属性(但我不确定(。欲了解更多信息,请参阅此处
,如果您通过一个函数传递两个指针,其中指针都声明为 restrict,您将摆脱别名。不过,这是非标准的编译器扩展,例如在 g++ 的情况下:
#include <cstdint>
#include <climits>
struct T{
uint8_t* target;
private:
void unpack3bit(char*__restrict__ source, int size, uint8_t*__restrict__ dst) {
while(size > 0){
uint64_t t = *source;
dst[0] = t & 0x7;
dst[1] = (t >> 3) & 0x7;
dst[2] = (t >> 6) & 0x7;
dst[3] = (t >> 9) & 0x7;
dst[4] = (t >> 12) & 0x7;
dst[5] = (t >> 15) & 0x7;
dst[6] = (t >> 18) & 0x7;
dst[7] = (t >> 21) & 0x7;
dst[8] = (t >> 24) & 0x7;
dst[9] = (t >> 27) & 0x7;
dst[10] = (t >> 30) & 0x7;
dst[11] = (t >> 33) & 0x7;
dst[12] = (t >> 36) & 0x7;
dst[13] = (t >> 39) & 0x7;
dst[14] = (t >> 42) & 0x7;
dst[15] = (t >> 45) & 0x7;
source+=6;
size-=6;
target+=16;
}
}
public:
void unpack3bit(char* source, int size) {
unpack3bit(source,size,this->target);
}
};
void f(int i, T& t, char* source) {
t.unpack3bit(source, i);
}
在线: http://goo.gl/SCjpL6
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组的地址分配给变量并删除
- 从C++本机插件更新Vector3数组
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 数组索引的值没有增加
- 将对象数组的引用传递给函数
- 为char数组调整zlib-zpipe
- 2D数组来自文本输入,中间有空格
- std::向量与传递值的动态数组
- 将具有不同字段的结构转换为 uint8 的数组
- UINT8数组对INT64的质量化失败,但应该起作用
- 将 UInt8 C++值转换为 C# 字节数组
- C 具有 uint8 数组奇怪行为的结构
- 正在从numpy.uint8的数组中提取无符号字符
- Jagged Uint8数组转换为C#字节
- 我如何将bitset转换为字节/uint8数组
- 转换uint8字节数组到任何WPF渲染对象
- 将UINT32值转换为UINT8数组[4]
- 将uint8的数组传递给函数会减小其大小(c++代码)