从成员指针到整个结构/类的转换 [英] Casting from member pointer to whole struct/class

查看:54
本文介绍了从成员指针到整个结构/类的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#include <iostream>


struct bar {
  double a = 1.0;
  int b = 2;
  float c = 3.0;
};

void callbackFunction(int* i) {

  auto myStruct = reinterpret_cast<bar*>(i) - offsetof(bar, b);

  std::cout << myStruct->a << std::endl;
  std::cout << myStruct->b << std::endl;
  std::cout << myStruct->c << std::endl;

  //do stuff
}

int main() {

  bar foo;

  callbackFunction(&foo.b);

  return 0;
}

我必须定义一个回调函数,并且我想在该函数中使用一些其他信息.我定义了自己的结构,并将成员的地址传递给函数.在该函数中,我想通过强制转换来检索"整个结构,但是指针似乎不匹配,因此我得到了错误的结果.我猜我在投射时做错了什么,但我不确定是什么?

I have to define a callback function and I want to use some additional information in that function. I defined my own struct and pass the address of a member to the function. In the function I want to "retrieve" the whole struct by casting, but the pointers don't seem to match and I get wrong results. I guess I'm doing something wrong while casting but I'm not sure what?

推荐答案

您缺少进行此项工作的演员表.您需要先将字节转换为字节类型,然后再减去偏移量,然后重铸回 bar * .原因是宏 offsetof 返回偏移量(以字节数为单位).当您执行指针算术时,减法和加法根据指针类型的大小进行.让我们举个例子:

You're missing a cast to make this work. You need to cast to a byte type before subtracting the offset, and then recast back to bar*. The reason is that the macro offsetof returns the offset as a number of bytes. When you do pointer arithmetic, subtraction and addition work in terms of the size of the pointed type. Let's make an example:

让我们假设您有一个名为 b bar 实例,其地址为0x100h.假设 sizeof(double)== 8 sizeof(int)== 4 sizeof(float)== 4 ,然后是 sizeof(bar)== 16 ,并且您的结构及其成员在内存中看起来像这样:

Let's assume that you have a bar instance, named b that is at address 0x100h. Assuming that sizeof(double) == 8, sizeof(int) == 4 and sizeof(float) == 4, then sizeof(bar) == 16 and your struct and its members would look like that in memory:

b @ 0x100h
b.a @ 0x100h
b.b @ 0x108h
b.c @ 0x10Ch

offsetof(bar,b)等于 8 .您的原始代码说处理0x108h,就好像指向 bar 类型的结构一样.然后给我一个地址为 0x108h-8 * sizeof(bar) bar 结构,或者特别是:0x108h-0x80h = 88h.希望该示例演示了为什么原始代码执行错误的计算.

offsetof(bar,b) would be equal to 8. Your original code says 'treat 0x108h as if it's pointing to a struct of type bar. then give me the bar struct at address 0x108h - 8 * sizeof(bar), or specifically: 0x108h - 0x80h = 88h.' Hopefully the example demonstrates why the original code was performing the wrong calculation.

这就是为什么您需要告诉编译器,您希望改为将地址减去字节数,以获取结构中第一个成员的正确地址.

This is why you need to tell the compiler that you want to subtract the addresses as bytes instead, to get to the correct address of the first member in your struct.

解决方案如下:

bar *所有者= reinterpret_cast< bar *>(reinterpret_cast< char *>(i)-offsetof(bar,b));

您应该非常注意的一件事:仅当 bar 标准布局时,这才是合法的.您可以使用模板 std :: is_standard_layout< bar> :: value 进行静态声明,以确认您没有意外调用UB.

One thing that you should be very careful about: This is legit only if bar is standard layout. You can use the template std::is_standard_layout<bar>::value to make a static assert to verify you're not accidentally invoking UB.

这篇关于从成员指针到整个结构/类的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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