【问题标题】:Data member/code pointer offsets数据成员/代码指针偏移
【发布时间】:2013-03-09 21:26:34
【问题描述】:

有人可以帮我理解下面的引语吗,因为我没听懂:

如果偏移量为 相对于结构或类开头的成员更少 大于 128。示例:

class S2{
    public:
    int a[100];   //400 bytes. first byte at 0, last byte at 399
    int b;        //4 bytes.   first byte at 400, last byte at 403
    int ReadB() {return b;}
};

这里b的偏移量是400。通过 a 访问 b 的任何代码 指针或成员函数如 ReadB() 需要加一个 4 字节 指针的偏移量。 如果 a 和 b 互换,那么两者都可以 使用 1 字节有符号整数偏移量访问

这个 1 字节的值从何而来?如果 a 和 b 交换 b 将从 0 字节开始,而 a 将从 4 字节开始?

编辑:我的错误,数组大小应该是 100

【问题讨论】:

  • 据我所知,数据成员在 C 中的对齐方式与 C++ 类似?
  • @userXXX 有可能,但这个问题是关于 C++ 的。 C中没有class

标签: c++ pointers memory memory-management


【解决方案1】:

他们试图指出的是,从结构开始到 bytes 中的b 成员的偏移量 > 255,因此无法用单个 8 位计算除了基指针。需要更多位:

Offset           Member
0                a    // offset always zero
100*sizeof(int)  b    // offset guaranteed to be at 100*sizeof(int)

反转字段顺序

0                b    // offset always zero
sizeof(int)*     a    // offset always sizeof(int) + potential padding

在第一种情况下访问 b 需要基指针 + 一个长度值,该长度值需要至少 16 位偏移量(假设您的最小实体是 8 位)。在第二种情况下,ba 都在适合 8 位的结构基地址的偏移范围内。

而且我发现这有点误导作者至少没有提到潜在的成员填充。

编辑 更新以反映成员 b 的 OP 从 400 个数组插槽更改为 100 个数组插槽。应该注意的是,如果这是一些具有 16 位实现 int 值的被破坏的嵌入式系统,作者指出的值将是错误的。在这种情况下,数组将是 100 * 2 - 字节宽,这仍然允许 8 位偏移量到达第二个成员。对于具有 4 字节(或更大)实现 int 值的系统,作者的观点是有效的。

【讨论】:

  • 除了关于对齐的明显缺失点之外,第一个成员不一定保证偏移量为 0。如果一个类型或其任何传递基类型具有虚拟成员,则第一个成员将在前面通过指向 vtable 的指针。在不检查标准的情况下,我猜这意味着无法保证数据成员的偏移量是多少,因为标准本身不涉及 vpointers 或 vtables。
  • @bitmask 标准,谢天谢地,至少明确了初始成员:事实上,它是唯一一个 is 保证始终具有已知偏移量的标准。根据 C++11 § 9.2,p20:“指向标准布局结构对象的指针,使用 reinterpret_cast 适当转换,指向其初始成员(或者如果该成员是位字段,则指向单元它所在的位置),反之亦然。 [注意:因此,标准布局结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。”
  • IIRC,这仅适用于 POD。具有虚拟成员函数的类的第一个成员肯定没有偏移量为零。
  • @bitmask 正确。我误解了您的原始评论,对此我深表歉意。可行的指针肯定需要在某处
【解决方案2】:

[在原始问题从a[400] 更改为a[100] 后编辑。]

他们的观点是正确的:

  • S2 结构中,a[100] 是 100 个 4 字节整数;所以实际上是 400 字节长。 a 因此具有 0 到 399 的偏移量。b(同样是 4 字节整数)将(至少)放置在 400-403 的偏移量处:

    Offset  data
    000-399 a[0]-a[99] inclusive
    400-403 b
    
  • 如果您要交换ab 的顺序,a 的偏移量将为 0-3,b 的偏移量将为 4-403:

    Offset  data
    000-003 b
    004-403 a[0]-a[99] inclusive
    
  • 在这两种情况下,访问 b 将使用 16 位偏移量,即使在数组的早期也是如此,因为可能需要偏移量范围。仅在第二种情况下,访问a 可以使用 8 位偏移量(取决于 CPU)来完成。这可以更快(取决于 CPU)。这完全是关于存储类存储位置和变量存储位置之间的偏移量所需的位数。

希望这会有所帮助。我在这里假设 4 字节整数(这很常见,但不是通用的),因为我认为原始引用它。

【讨论】:

  • ints 不一定是 4 个字节。
  • 我很抱歉,但数组大小应该是 100。我输入错误 - 已编辑我的问题。
  • @NeilTownsend:我认为在你的第二个要点中你得到了 ab 倒退。 b 是单个 int,a 是数组。除非你也交换了名字,但这只是令人困惑
  • 所以简而言之,如果我理解的话,我们正在查看第一个数据成员和最后一个数据成员的字节边界之间的字节距离?重新排列意味着 b 和 a 之间的距离小于 256- 即我们可以使用一个字节作为它们的地址偏移量?
  • @user997112:是的,你明白了。他们在问题中引用的 1 字节是保存偏移量所需的内存量。如果两个偏移量都小于 256,则两个偏移量的值可以保存在一个字节中。
【解决方案3】:

这里指的是存储偏移量所需的空间。在给出的示例中,a 位于偏移量 0(需要 1 个字节来表示),b 位于偏移量 400*sizeof(int)(实际上可能需要 4 个字节)。如果交换它们,则a 位于偏移量 0(1 个字节),b 位于偏移量 4(1 个字节)。

【讨论】:

  • 我认为您的意思是“a 在偏移量 4 处?”所以我们所说的是 1 个字节,即 2^8 和 256,将允许我们引用数据成员字节边界的位置?如果我们有第三个数组,我们可能需要一个短整数指针来确保我们引用超过 256 的字节偏移量?
猜你喜欢
  • 2011-08-02
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2019-06-23
相关资源
最近更新 更多