当前位置: 首页 > 知识库问答 >
问题:

从成员指针到整个结构/类的强制转换

卫甫
2023-03-14

考虑以下代码

#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;
}

我必须定义一个回调函数,我想在该函数中使用一些附加信息。我定义了自己的结构并将成员的地址传递给函数。在函数中,我想通过强制转换“检索”整个结构,但指针似乎不匹配,我得到了错误的结果。我想我在选演员时做错了什么,但我不确定是什么?

共有3个答案

杨鸿畅
2023-03-14

您将指针向后移动了太多,偏移量bsizeof(double)8,但表达式

虽然从技术上讲,将结构/类投射到它的第一个成员是合法的,但你永远不需要这样做,它很容易导致UB。

公孙棋
2023-03-14

问题是,使用reinterpret_cast

这是有问题的,因为对于任何指针(或数组)p 和索引 i,表达式 *(p i) 完全等于 p[i]

所以整个表达式reinterpret_cast

如果你有一个字节的“数组”,而不是柱结构的“数组”,它就会起作用:

char* tempPtr = reinterpret_cast<char*>(i) - offsetof(bar, b);
bar* myStructPtr = reinterpret_cast<bar*>(tempPtr);

暨成双
2023-03-14

您缺少一个转换来完成这项工作。在减去偏移量之前,您需要转换为字节类型,然后重新转换回bar*。原因是宏offsetof以字节数的形式返回偏移量。当您进行指针算术时,减法和加法根据指向类型的大小进行工作。让我们举个例子:

让我们假设您有一个bar实例,名为b,位于地址0x100h。假设sizeof(Double)==8sizeof(int)==4sizeof(浮点数)==4,那么sizeof(bar)==16和您的结构及其成员在内存中的样子:

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

< code>offsetof(bar,b)将等于< code>8。您的原始代码说‘将0x108h视为指向< code>bar类型的结构。然后给我地址为< code > 0x 108h-8 * sizeof(bar)的< code>bar结构,具体来说就是:0x108h - 0x80h = 88h。”希望这个例子演示了为什么原始代码执行了错误的计算。

这就是为什么您需要告诉编译器,您想将地址减去为字节,以获得结构中第一个成员的正确地址。

解决方案如下:

< code > bar * owner = reinterpret _ cast

有一件事你应该非常小心:只有当bar是标准布局时,这才是合法的。您可以使用模板std::is_standard_layout

 类似资料:
  • 假设代码是用c11编译的,并且启用了严格别名。 我不是在寻找一种不同的方法,我想专注于这个具体的问题,以及它是否可行或为什么不可行。 (如果我无意中犯了一些无关的错误,请告诉我,我会改正的) C11标准说: 6.2.5.28所有指向结构类型的指针应具有彼此相同的表示和对齐要求。 6.7.2.1.6结构是由成员序列组成的类型,其存储按有序顺序分配 这意味着结构A和B中指针的大小和对齐方式相同。 结构

  • C标准规定: 指向结构对象的指针,经过适当的强制转换,指向其初始成员(如果该成员是位字段,则指向其所在的单元),反之亦然。 如果有问题的结构的第一个成员是匿名结构/联合,是否有任何可能(并且定义良好)的方法在C11中执行这种“合适的转换”?或者如果包含的结构是匿名的,则执行“反之亦然”的反向转换? 我猜想,转换为与匿名结构具有相同成员序列的非匿名结构会使它无法很好地定义,因为它们不兼容,因此不能保

  • 指针变量数据类型的强制转换 必须显式强制类型转换,不允许隐式类型转换 指向空间的强制类型转换,本质上就是普通变量的强制类型转换 int a = 10; float b = 3.14; int *pa = &a; float *pb = &b; *pa = (int)*pb; // 等价于 a = (int)b; 指针本身强制类型转换,改变的是对其指向空间的引用方式(空间大小和存储结构) int

  • 我正在学习如何在C中使用并写了以下示例: 问:是否保证在所有情况下指向一个结构的指针都是指向它的第一个元素的完全相同的指针? 在这种特殊的情况下,它能像我预期的那样工作,但我不确定它是否能得到保证。编译器可以在开始时插入一些填充吗? 我唯一能找到的关于结构类型布局的是N1570的类型: 结构类型描述了一组按顺序分配的非空成员对象(在某些情况下,还包括一个不完整的数组),每个对象都有一个可选的指定名

  • 我遇到了一个语法问题。看另一个StackOverflow答案并不能给出一个适用于我的问题的答案。至少不是我能理解的。 我的计划程序类: 这一切都编译得很好,但问题在于调用该函数中的成员函数指针: 编译这个会给我带来错误; 其他尝试: 有人能帮我解释一下我缺了什么知识吗?

  • 公有派生类的对象可作为其相应基类的对象处理,这使得一些有意义的操作成为可能。例如,从某个特定基类派生出来的各种类,尽管这些类的对象彼此之间互不相同,但是仍然能够建立这些对象的链表,只要把这些对象作为基类对象处理就可以了。然而反过来是不行的,基类的对象不能自动成为派生类的对象。 常见编程错误 9.1 将基类对象作为派生类对象处理。 程序员可以用显式类型转换把基类指针强制转换为派生类指针。但是,如果要