提问者提出一个关于#define offsetof(st, m) \
((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
deference null(0)指针的问题,并且没有段错误。
- >运算符在上面使用但它不用于访问该值。 相反,它用于获取值的地址。这里有一个 应该让它更清晰的非宏代码示例
SomeType *pSomeType = GetTheValue(); int* pMember = &(pSomeType->SomeIntMember);
第二行实际上不会导致解除引用(实现 依赖)。它只返回SomeIntMember的地址 pSomeType值。
我的问题是如何证明int* pMember = &(pSomeType->SomeIntMember);
只是将someIntMember的地址分配给pMember而不引用pSomeType。
有没有iso c ++标准?或者有什么方法吗?
虽然我发布的问题是c,我想要c ++答案,所以我将这个问题标记为c ++。
如果c ++标准中有什么内容,那就更好了。
否则,我希望看到一些证明JaredPar结论的东西,例如xaxxon发布了assembly,或者具体的编译器如何实现。
如果答案持有int* pMember = &(pSomeType->SomeIntMember);
确实对pSomeType有所帮助,那么为什么offsetof的实现(#define offsetof(st, m) ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
)有效?
感谢所有的评论和答案,现在我明白#define offsetof(st, m) ((size_t) ( (char*)&((st*)(0))->m - (char)0))
是c中的实现之一,而不是c ++中的实现。
另外,我发现了msvc的实现,#define offsetof(s,m) ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
,但它对我来说有点复杂,有人可以表达一下吗?提前致谢。
答案 0 :(得分:2)
->
运算符会导致取消引用。如果a -> b
是指针,则(*a).b
定义为a
。
如果人们声称这不是一个解除引用,那么他们要么弄错了,要么使用“#34; dereference&#34;”这个词的一些非标准含义。
在C ++标准中,*
的正式名称是间接运算符。单词&#34; dereference&#34;不用作动词;相反,标准表示将*
运算符应用于指针会产生一个左值,用于指定指向的对象。
&(p->x)
不是有效指针, p
会导致未定义的行为。
关于&#34;偏移&#34;编辑时,实现标头中的代码不受语言规则的约束。它们可以包含魔术和非标准的非可移植代码。
答案 1 :(得分:0)
当M.M's answer指出时,->
运算符 是一个解除引用(如果操作数是指针)。关于这是否解除引用的困惑可能源于相关的内存访问概念。
取消引用指针是将对象放在指向的地址处。或者更准确地说,给定p
类型的指针T*
,表达式*p
是类型T
的左值,它引用指向的对象。
内存访问是指发生读取或写入时,分别对应于左值到右值的转换和赋值。如果没有发生,则无法访问内存。
pSomeType->SomeIntMember // is defined to be...
(*pSomeType).SomeIntMember
*pSomeType
是SomeType
的左值,因此其成员SomeIntMember
是int
的左值。
然后是它的地址。没有左值到右值的转换,也没有分配,因此没有内存访问,如@ xaxxon的评论所示。