Suppose there's a structure
假设有一个结构
struct Thing {
int a;
bool b;
};
and I get a pointer to member b
of that structure, say as parameter of some function:
我得到一个指向该结构的成员b的指针,作为某个函数的参数:
void some_function (bool * ptr) {
Thing * thing = /* ?? */;
}
How do I get a pointer to the containing object? Most importantly: Without violating some rule in the standard, that is I want standard defined behaviour, not undefined nor implementation defined behaviour.
如何获取指向包含对象的指针?最重要的是:如果不违反标准中的某些规则,那就是我需要标准定义的行为,而不是未定义的行为,也不是实现定义的行为。
As side note: I know that this circumvents type safety.
作为旁注:我知道这可以避免类型安全。
4 个解决方案
#1
15
If you are sure that the pointer is really pointing to the member b
in the structure, like if someone did
如果你确定指针真的指向结构中的成员b,就像有人做的那样
Thing t;
some_function(&t.b);
Then you should be able to use the offsetof
macro to get a pointer to the structure:
然后你应该能够使用offsetof宏来获得指向结构的指针:
std::size_t offset = offsetof(Thing, b);
Thing* thing = reinterpret_cast<Thing*>(reinterpret_cast<int8_t*>(ptr) - offset);
Note that if the pointer ptr
doesn't actually point to the Thing::b
member, then the above code will lead to undefined behavior if you use the pointer thing
.
请注意,如果指针ptr实际上没有指向Thing :: b成员,那么如果使用指针,上面的代码将导致未定义的行为。
#2
4
void some_function (bool * ptr) {
Thing * thing = (Thing*)(((char*)ptr) - offsetof(Thing,b));
}
I think there is no UB.
我认为没有UB。
#3
3
X* get_ptr(bool* b){
static typename std::aligned_storage<sizeof(X),alignof(X)>::type buffer;
X* p=static_cast<X*>(static_cast<void*>(&buffer));
ptrdiff_t const offset=static_cast<char*>(static_cast<void*>(&p->b))-static_cast<char*>(static_cast<void*>(&buffer));
return static_cast<X*>(static_cast<void*>(static_cast<char*>(static_cast<void*>(b))-offset));
}
First, we create some static storage that could hold an X
. Then we get the address of the X
object that could exist in the buffer, and the address of the b
element of that object.
首先,我们创建一个可以容纳X的静态存储。然后我们得到缓冲区中可能存在的X对象的地址,以及该对象的b元素的地址。
Casting back to char*
, we can thus get the offset of the bool
within the buffer, which we can then use to adjust a pointer to a real bool
back to a pointer to the containing X
.
回到char *,我们可以得到缓冲区中bool的偏移量,然后我们可以使用它来调整指向真实bool的指针,返回指向包含X的指针。
#4
1
My proposal is derived from the @Rod answer in Offset from member pointer without temporary instance, and the similar @0xbadf00d's one in Offset of pointer to member.
我的建议来自Offset中的@Rod答案,没有临时实例的成员指针,以及类似的@ 0xbadf00d在指向成员的指针的偏移量中的一个。
I started imagining a form of offset driving the implementation of a pointer to a class data member, later confirmed by the post in question and the tests i've made.
我开始想象一种偏移形式驱动指向类数据成员的指针的实现,稍后由相关帖子和我所做的测试确认。
I'm not a C++ practitioner so sorry for the brevity.
我不是C ++从业者,为了简洁而感到抱歉。
#include <iostream>
#include <cstddef>
using namespace std;
struct Thing {
int a;
bool b;
};
template<class T, typename U>
std::ptrdiff_t member_offset(U T::* mem)
{
return
( &reinterpret_cast<const char&>(
reinterpret_cast<const T*>( 1 )->*mem )
- reinterpret_cast<const char*>( 1 ) );
}
template<class T, typename U>
T* get_T_from_data_member_pointer (U * ptr, U T::*pU) {
return reinterpret_cast<T*> (
reinterpret_cast<char*>(ptr)
- member_offset(pU));
}
int main()
{
Thing thing;
thing.b = false;
bool * ptr = &thing.b;
bool Thing::*pb = &Thing::b;
std::cout << "Thing object address accessed from Thing test object lvalue; value is: "
<< &thing << "!\n";
std::cout << "Thing object address derived from pointer to class member; value is: "
<< get_T_from_data_member_pointer(ptr, &Thing::b) << "!\n";
}
#1
15
If you are sure that the pointer is really pointing to the member b
in the structure, like if someone did
如果你确定指针真的指向结构中的成员b,就像有人做的那样
Thing t;
some_function(&t.b);
Then you should be able to use the offsetof
macro to get a pointer to the structure:
然后你应该能够使用offsetof宏来获得指向结构的指针:
std::size_t offset = offsetof(Thing, b);
Thing* thing = reinterpret_cast<Thing*>(reinterpret_cast<int8_t*>(ptr) - offset);
Note that if the pointer ptr
doesn't actually point to the Thing::b
member, then the above code will lead to undefined behavior if you use the pointer thing
.
请注意,如果指针ptr实际上没有指向Thing :: b成员,那么如果使用指针,上面的代码将导致未定义的行为。
#2
4
void some_function (bool * ptr) {
Thing * thing = (Thing*)(((char*)ptr) - offsetof(Thing,b));
}
I think there is no UB.
我认为没有UB。
#3
3
X* get_ptr(bool* b){
static typename std::aligned_storage<sizeof(X),alignof(X)>::type buffer;
X* p=static_cast<X*>(static_cast<void*>(&buffer));
ptrdiff_t const offset=static_cast<char*>(static_cast<void*>(&p->b))-static_cast<char*>(static_cast<void*>(&buffer));
return static_cast<X*>(static_cast<void*>(static_cast<char*>(static_cast<void*>(b))-offset));
}
First, we create some static storage that could hold an X
. Then we get the address of the X
object that could exist in the buffer, and the address of the b
element of that object.
首先,我们创建一个可以容纳X的静态存储。然后我们得到缓冲区中可能存在的X对象的地址,以及该对象的b元素的地址。
Casting back to char*
, we can thus get the offset of the bool
within the buffer, which we can then use to adjust a pointer to a real bool
back to a pointer to the containing X
.
回到char *,我们可以得到缓冲区中bool的偏移量,然后我们可以使用它来调整指向真实bool的指针,返回指向包含X的指针。
#4
1
My proposal is derived from the @Rod answer in Offset from member pointer without temporary instance, and the similar @0xbadf00d's one in Offset of pointer to member.
我的建议来自Offset中的@Rod答案,没有临时实例的成员指针,以及类似的@ 0xbadf00d在指向成员的指针的偏移量中的一个。
I started imagining a form of offset driving the implementation of a pointer to a class data member, later confirmed by the post in question and the tests i've made.
我开始想象一种偏移形式驱动指向类数据成员的指针的实现,稍后由相关帖子和我所做的测试确认。
I'm not a C++ practitioner so sorry for the brevity.
我不是C ++从业者,为了简洁而感到抱歉。
#include <iostream>
#include <cstddef>
using namespace std;
struct Thing {
int a;
bool b;
};
template<class T, typename U>
std::ptrdiff_t member_offset(U T::* mem)
{
return
( &reinterpret_cast<const char&>(
reinterpret_cast<const T*>( 1 )->*mem )
- reinterpret_cast<const char*>( 1 ) );
}
template<class T, typename U>
T* get_T_from_data_member_pointer (U * ptr, U T::*pU) {
return reinterpret_cast<T*> (
reinterpret_cast<char*>(ptr)
- member_offset(pU));
}
int main()
{
Thing thing;
thing.b = false;
bool * ptr = &thing.b;
bool Thing::*pb = &Thing::b;
std::cout << "Thing object address accessed from Thing test object lvalue; value is: "
<< &thing << "!\n";
std::cout << "Thing object address derived from pointer to class member; value is: "
<< get_T_from_data_member_pointer(ptr, &Thing::b) << "!\n";
}