如何便携式使用指针的低位作为标志? [英] How portable is using the low bit of a pointer as a flag?

查看:118
本文介绍了如何便携式使用指针的低位作为标志?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果有一个类需要一个指针和 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, and uint8_t. (And that assumes CHAR_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆