【问题标题】:Correct usage of offsetof macro正确使用 offsetof 宏
【发布时间】:2012-03-03 17:23:33
【问题描述】:

我正在尝试通过以下方式使用 offsetof 宏:

typedef unsigned char u8;
typedef unsigned short u16;

struct MapBlock
{
  u16 type : 10;
  u8 variant : 3;
  bool isTop : 1;
};

struct MapTile
{
  struct MapBlock top, middle;
  u16 x;
  u8 y;
};

MapTile *tfb(struct MapBlock *block)
{
  if (block->isTop)
    return (MapTile*)block;
  else
    return (MapTile*)((u8*)block - offsetof(struct MapTile, middle));
}

它似乎适用于这个简单的测试用例:

for (int i = 0; i < width; ++i)
  for (int j = 0; j < height; ++j)
  {
    map[i][j].x = i;
    map[i][j].y = j;
    map[i][j].top.isTop = true;
    map[i][j].middle.isTop = false;
  }

printf("%p == %p == %p\n",tfb(&map[40][50].top),tfb(&map[40][50].middle),&map[40][50]);

现在是真正的问题:

  • 安全吗? (假设使用 g++
  • 它是否适用于任何标准优化? (主要是-O2
  • 有没有更好的方法来做我正在做的事情? (我需要这样做以避免为每个 MapBlock 存储 xy 但能够在不知道相关 MapTile 的情况下通过块访问它们)
  • 在减去偏移量时可以避免转换为u8 吗?我想没有,但我只是想确定一下..

谢谢

【问题讨论】:

  • 这对于试图阅读该代码的人来说绝对是不安全的。
  • 这不是我要问的,因为我是唯一一个处理代码的人,如果我正在寻找一种可以节省一些字节的解决方案,这意味着我真的需要它,不要你不觉得吗? :)
  • 您的tfb 函数清楚地假定top 将是结构中的第一件事。为什么不一直这样做,并假设它紧随其后的是middle?然后你可以写(MapTile*)(block - 1),这不是面向未来但更清晰。
  • MapTile 结构不会改变,所以我绝对可以做到。我只是想我最终会得到同样的东西,因为offsetof 是一个宏
  • 你可以让 top 和 middle 成为一个二元素数组,那么减 1 技巧是安全的。但我相信你的 offsetof 很好;你已经遵守了规则,所以编译的必须正确翻译它。

标签: c++ c pointers pointer-arithmetic offsetof


【解决方案1】:

实际上,我的解决方案似乎一切正常。 cmets 中建议的优化(使用block - 1)也确实有效,所以如果您有类似的问题,请随意使用我的示例!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多