中的\'offsetof\'宏是否会调用未定义的行为?
|
来自MSVC \的实现示例:
#define offsetof(s,m) \\
(size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
// ^^^^^^^^^^^
可以看出,它取消引用了空指针,该指针通常会调用未定义的行为。这是规则的例外还是正在发生的事情?
没有找到相关结果
已邀请:
6 个回复
旅牢斯讲
的例外表示它不是UB。 您可以肯定地说的是,将
与非POD类型一起使用是UB。 (2)代码UB是否与为其编写的编译器有关? 不,当然不是。 给定编译器的编译器供应商代码可以使用该编译器的任何功能。 干杯,……
咖哀烈
眠皇
如果ѭ5和ѭ6是不相关的指针,则ѭ7的计算将产生未定义的行为。但是,在某些平台上,
和
之间的关系使得给定任何
,计算
将始终等于
。在做出上述保证的平台上,ѭ13的上述实现将是合法的(并且在某些此类平台上可能比任何可行的替代方案都快)。但是,在某些其他平台上,此类功能可能总是会失败,除非两个字符串都属于同一分配对象。 相同的原理适用于
宏。不需要编译器提供任何方式来获得等同于ѭ2behavior的行为(而不是通过实际使用该宏)。如果编译器的指针算术模型使得可以通过在对象上使用
运算符来获得所需的
行为。空指针,那么它的
宏可以做到这一点。如果编译器不支持在指向该类型实例的合法指针以外的任何地方使用
的工作,则它可能需要定义一个内部函数来计算字段偏移量并定义field2ѭ宏以使用该字段。重要的不是标准定义了使用标准库宏和函数执行的动作的行为,而是实现方式确保了此类宏和函数的行为符合要求。
喷乡顾沥沪
显然,不会对目标
生成任何内存访问,因为它是
,并且禁止编译器生成对
变量的虚假访问。但是“ 25”不是易失性的,因此编译器可能会生成对其的访问。根据标准,运算符的地址或转换为引用类型均不会创建未评估的上下文。 因此,我看不出有任何理由要求使用“ 23”,并且我同意其他人的看法,这是根据标准的未定义行为。当然,任何编译器都可以在标准留给实现者指定或未定义的地方定义行为。 最后,第ѭ27节中的注释说 特别是,空引用不能存在于定义良好的程序中,因为创建这种引用的唯一方法是将其绑定到通过解引用空指针而获得的“对象”,这会导致未定义的行为。
肉脓措伪
在结构
中的偏移量为0,以及在某些其他情况下,这在C ++中不是未定义的行为。根据第232期(重点是我的): 一元*运算符执行间接操作:应用该表达式的表达式应为指向对象类型的指针或为函数类型的指针,并且结果为引用表达式所指向的对象或函数的左值(如果有) 。如果指针是空指针值(7.11 [conv.ptr])或指向数组对象的最后一个元素(8.7 [expr.add])的最后一个,则结果为空的左值,并且不引用任何对象或功能。空的左值不可修改。 因此,仅当
既不在偏移量0处,也不在对应于比数组对象的最后一个元素晚一个地址的偏移量时,才是未定义的行为。请注意,在C ++中允许向
添加0偏移,但在C中不允许。 正如其他人指出的那样,编译器被允许(并且极有可能)永远不会创建未定义的行为,并且可以与使用特定编译器的增强规范的库一起打包。
冉案
的地址。它没有取消引用空指针。