如何便携式使用指针的低位作为标志? [英] How portable is using the low bit of a pointer as a flag?
问题描述
如果有一个类需要一个指针和 bool
。为了简单起见,在示例中将使用 int
指针,但是指针类型是不相关的,只要它指向 size()
大于1。
If there is for example a class that requires a pointer and a bool
. For simplicity an int
pointer will be used in examples, but the pointer type is irrelevant as long as it points to something whose size()
is more than 1 .
使用 {bool,int *}
定义类导致类的大小是指针大小的两倍和大量的浪费空间
Defining the class with { bool , int *}
data members will result in the class having a size that is double the size of the pointer and a lot of wasted space
如果指针不指向 char
(或 size(1)
的其他数据),那么可以认为低位将始终为零。类可以定义 {int *}
或为了方便起见: union {int *,uintptr_t}
If the pointer does not point to a char
(or other data of size(1)
), then presumably the low bit will always be zero. The class could defined with {int *}
or for convenience: union { int *, uintptr_t }
bool
是通过根据逻辑 bool >设置/清除指针的低位来实现的
值,并在需要使用指针时清除该位。
The bool
is implemented by setting/clearing the low bit of the pointer as per the logical bool
value and clearing the bit when you need to use the pointer.
定义的方式:
struct myData
{
int * ptr;
bool flag;
};
myData x;
// initialize
x.ptr = new int;
x.flag = false;
// set flag true
x.flag = true;
// set flag false
x.flag = false;
// use ptr
*(x.ptr)=7;
// change ptr
x = y; // y is another int *
建议的方法:
union tiny
{
int * ptr;
uintptr_t flag;
};
tiny x;
// initialize
x.ptr = new int;
// set flag true
x.flag |= 1;
// set flag false
x.flag &= ~1;
// use ptr
tiny clean=x; // note that clean will likely be optimized out
clean.flag &= ~1; // back to original value as assigned to ptr
*(clean.ptr)=7;
// change ptr
bool flag=x.flag;
x.ptr = y; // y is another int *
x.flag |= flag;
这似乎是未定义的行为,但这是怎么移植的?
This seems to be undefined behavior, but how portable is this?
推荐答案
只要在尝试将指针用作指针之前恢复指针的低位,则可能 可移植,只要你的系统,你的C ++实现和你的代码符合一定的假设。
As long as you restore the pointer's low-order bit before trying to use it as a pointer, it's likely to be "reasonably" portable, as long as your system, your C++ implementation, and your code meet certain assumptions.
我不一定能给你一个完整的假设列表,我的头顶:
I can't necessarily give you a complete list of assumptions, but off the top of my head:
- 你不指向任何大小为1字节的内容。这不包括
char
,unsigned char
,signed char
code> int8_t 和uint8_t
。 (假设CHAR_BIT == 8
;在具有例如16位或32位字节的外来系统上,可以排除其他类型。) - 大小至少为2字节的对象总是在偶数地址对齐。注意,x86不需要 你可以在一个奇数地址访问一个4字节
int
,但它会稍慢一些。但编译器通常安排对象存储在偶数地址。其他架构可能有不同的要求。 - 指向偶数地址的指针的低位设置为0.
- You're not pointing to anything whose size is 1 byte. This excludes
char
,unsigned char
,signed char
,int8_t
, anduint8_t
. (And that assumesCHAR_BIT == 8
; on exotic systems with, say, 16-bit or 32-bit bytes, other types might be excluded.) - Objects whose size is at least 2 bytes are always aligned at an even address. Note that x86 doesn't require this; you can access a 4-byte
int
at an odd address, but it will be slightly slower. But compilers typically arrange for objects to be stored at even addresses. Other architectures may have different requirements. - A pointer to an even address has its low-order bit set to 0.
对于最后一个假设,我实际上有一个具体的反例。在Cray向量系统(J90,T90和SV1是我自己使用的)中,一个机器地址指向一个64位的字,但是Unicos下的C编译器设置 CHAR_BIT == 8
。字节指针以软件实现,其中存储在64位指针的其它未使用的高位 3位中的字内的3位字节偏移。因此,指向8字节对齐对象的指针可以容易地将其低阶位设置为1.
For that last assumption, I actually have a concrete counterexample. On Cray vector systems (J90, T90, and SV1 are the ones I've used myself) a machine address points to a 64-bit word, but the C compiler under Unicos sets CHAR_BIT == 8
. Byte pointers are implemented in software, with the 3-bit byte offset within a word stored in the otherwise unused high-order 3 bits of the 64-bit pointer. So a pointer to an 8-byte aligned object could have easily its low-order bit set to 1.
已经有Lisp实现(示例,它们使用指针的低2位来存储类型标签。我模糊地回忆起在移植过程中会导致严重的问题。
There have been Lisp implementations (example that use the low-order 2 bits of pointers to store a type tag. I vaguely recall this causing serious problems during porting.
底线:大多数系统可能可以使用它,未来的架构是不可预测的,
Bottom line: You can probably get away with it for most systems. Future architectures are largely unpredictable, and I can easily imagine your scheme breaking on the next Big New Thing.
有些事情要考虑:
你可以将布尔值存储在您的类外的位向量 (保持指针和位向量中的相应位之间的关联作为练习)。
Can you store the boolean values in a bit vector outside your class? (Maintaining the association between your pointer and the corresponding bit in the bit vector is left as an exercise).
考虑将代码添加到所有失败的指针操作,如果它看到一个指针的低位设置为1,则会出现错误消息。使用 #ifdef
删除生产版本中的检查代码。如果您在某些平台上开始遇到问题,请在启用检查的情况下创建一个版本的代码。看看会发生什么。
Consider adding code to all pointer operations that fails with an error message if it ever sees a pointer with its low-order bit set to 1. Use #ifdef
to remove the checking code in your production version. If you start running into problems on some platform, build a version of your code with the checks enabled and see what happens.
我怀疑,随着应用程序的增长很少收缩),你会想要存储不仅仅是一个 bool
和你的指针。如果发生这种情况,空间问题就会消失,因为你已经使用了额外的空间。
I suspect that, as your application grows (they seldom shrink), you'll want to store more than just a bool
along with your pointer. If that happens, the space issue goes away, because you're already using that extra space anyway.
这篇关于如何便携式使用指针的低位作为标志?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!