如何证明 -> 在 int* pMember = &(pSomeType->SomeIntMember) 时不用于顺从;

How to prove -> is not used to deference when int* pMember = &(pSomeType->SomeIntMember);

本文关键字:gt SomeIntMember pSomeType- 用于 证明 何证明 int pMember      更新时间:2023-10-16

在这个问题上:

asker 提出了一个关于#define offsetof(st, m) ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))顺从 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发布了程序集,或者特定的编译器如何实现。

如果答案成立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))),但这对我来说有点复杂,有人可以表达吗?提前谢谢。

->运算符确实会导致取消引用。a -> b定义为(*a).b,如果a是一个指针。

如果人们声称它不是取消引用,那么他们要么是错误的,要么使用了"取消引用"一词的一些非标准含义。

在C++标准中,*的正式名称是间接寻址运算符。 "取消引用"一词不用作动词;相反,该标准说,将*运算符应用于指针会产生一个指示所指向对象的左值。

如果&(p->x)不是有效的指针,则p会导致未定义的行为。

关于"offsetof"编辑,实现头文件中的代码不受语言规则的约束。它们可以包含魔术和非标准的不可移植代码。

正如 M.M 的回答所指出的,->运算符是取消引用(如果操作数指针(。关于这是否是取消引用的混淆可能源于内存访问的相关概念。

取消引用指针就是获取指向地址处的对象。或者更准确地说,给定一个指针p类型为T*,表达式*pT类型的左值,指的是指向的对象。

内存访问是指发生读取或写入,分别对应于左值到右值的转换和分配。当不发生任何操作时,不会访问内存。

pSomeType->SomeIntMember    // is defined to be...
(*pSomeType).SomeIntMember

*pSomeTypeSomeType的左值,因此其成员SomeIntMemberint的左值。

然后它的地址被占用。没有发生左值到重值的转换,也没有发生赋值,因此没有内存访问,如@xaxxon的评论所示。