【问题标题】:Determining struct member byte-offsets at compile-time?在编译时确定结构成员字节偏移量?
【发布时间】:2023-03-12 23:34:01
【问题描述】:

我想在编译时找到结构成员的字节偏移量。例如:

struct vertex_t
{
    vec3_t position;
    vec3_t normal;
    vec2_t texcoord;
}

我想知道normal 的字节偏移量是(在这种情况下应该是12。)

我知道我可以使用offsetof,但这是一个运行时函数,我不想使用它。

我正在努力实现的目标是否可能?

编辑offsetof 是编译时,我的错!

【问题讨论】:

  • 为什么你不想使用offsetof
  • @ViníciusGobboA.deOliveira 因为它是一个运行时函数,我希望在编译时收集这些信息,这样我就不需要使用 CPU 周期。
  • offsetof 在编译时计算。 C++ 标准遵循 C 标准,C 标准根据 7.17(3) 规定它“扩展为整数常量表达式”。

标签: c++ struct offset compile-time offsetof


【解决方案1】:

offsetof 是一个编译时间常数,如果我们看一下 C++ 标准部分草案C.3 C 标准库2 说:

C++ 标准库提供了来自 C 库的 57 个标准宏,如表 149 所示。

并且该表包括offsetof。如果我们去C99草案标准部分7.17通用定义3段包括:

offsetof(type, member-designator)

扩展为具有 size_t 类型的整数常量表达式,其值 这是以字节为单位的偏移量 [...]

【讨论】:

  • 宾果游戏。我想知道这是否是 C99 的功能? (作为 ICE,而不是宏本身。)
  • @Potatoswatter 从这个previous answer 链接的草案 C89 文本具有相同的语言。
【解决方案2】:

在 C 中:

offsetof 通常实际上是一个宏,并且由于它的定义,它可能会被编译器优化,以便它减少到一个常量值。即使它确实变成了一个表达式,它也足够小,几乎不会造成任何开销。

例如在文件stddef.h处,定义为:

#define offsetof(st, m) ((size_t)(&((st *)0)->m))

在 C++ 中:

事情变得有点复杂,因为它必须将成员的偏移量解析为方法和其他变量。所以offsetof被定义为一个宏来调用另一个方法:

#define offsetof(st, m) __builtin_offsetof(st, m)

如果您只需要它用于结构,那么offsetof 就足够了。否则,我认为这是不可能的。

【讨论】:

  • 这些是示例定义。该标准没有指定offsetof 的定义方式,只是它的行为方式。
  • 在 C++ 中,offsetof 是未定义的,除非在标准布局结构上。 “优化”为常量值仍然不会使其成为一个整数常量表达式。
  • @KeithThompson 你是对的。我从我现在使用的 libc 版本中获取了这些定义。
  • @Potatoswatter 你是对的。按照我的理解,每个具有适当标志的现代编译器很可能将整个表达式简化为一个常量值,因为它很可能成为一个只有常量操作数的表达式。我的答案应该更清楚。感谢您的评论!
  • 在C语言中,offsetof必须是宏,并且需要展开成整数常量表达式。请参阅 N1570 7.19 第 3 段。C++ 还要求 offsetof 是一个宏 (C++12 18.2 [support.types])。 C++ 在继承自 C 的基础上增加了一段描述;我不太了解 C++,无法判断 C++ 规则是否暗示 offsetof 必须扩展为整数常量表达式。
【解决方案3】:

你确定它是运行时的吗?

以下作品..

#include <iostream>
#include <algorithm>


struct vertex_t
{
    int32_t position;
    int32_t normal;
    int32_t texcoord;
};

const int i = offsetof(vertex_t, normal); //compile time..

int main()
{
    std::cout<<i;
}

另见此处:offsetof at compile time

【讨论】:

  • 在 C++ 中,const int 的初始值设定项不需要在编译时确定。尝试使用offsetof 作为绑定数组。
  • 来自:stackoverflow.com/questions/436300/… The implementation is free to calculate it at runtime, but it must also be able to calculate it at compile time, because it must give a diagnostic message if a constant expression is not representable in the type that its expression has and if such expressions are allowed in contexts that require the value at translation time, for example if used as the size of an array dimension. 所以是的,它确实需要在编译时确定。
  • 不,const 对象的初始化器不是常量表达式。
  • offsetof 扩展为常量表达式。从什么时候开始“原始类型”成为对象?如果它不是一个常量表达式,那么它只是一个在编译时分配的常量值。
  • C 和 C++ 中原始类型的实例被称为对象,就像类类型的实例一样。 C 需要在编译时解析,但 C++ 将执行您想要的任何运行时任务。试试std::ostream &amp;my_os = std::cout &lt;&lt; "hello, world\n";
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多