为什么重新定义sizeof有效

时间:2014-02-25 16:46:36

标签: c memory c-preprocessor sizeof

我正在将sizeof重新定义为:

#undef sizeof
#define sizeof(type)  ((char*)((type*)(0) + 1) - (char*)((type*)(0)))

为此,定义中的2'0'需要与内存中的实体相同,换句话说,需要具有相同的地址。这总是有保证,还是编译器/体系结构/运行时依赖?

4 个答案:

答案 0 :(得分:1)

这里的0不是对象 - 它是一个地址。所以你提出的问题是一个不合理的问题。

答案 1 :(得分:1)

您认为零是需要存储在某处的谨慎的数据片段。它们不是......它们被作为指向内存位置零的指针。

当您将指针递增到某个类型时,它实际上会增加它指向的类型的大小。这就是C数组算法的工作原理。

答案 2 :(得分:1)

实际上,某种类型的空指针总是指内存中的相同位置(特别是当构造方式与上面相同时),因为任何其他实现都是毫无意义的。

然而,标准实际上并不能保证很多:

  • “[...]保证比较不等于指向任何对象或函数的指针。” 6.3.2.3§3
  • “[...]任何两个空指针都应该相等。” 6.3.2.3§4

这留下了许多背风。假设具有两个不同区域的存储器模型。每个区域可以有一个空指针区域(比如前128个字节)。很容易看出,即使在那种奇怪的情况下,关于空指针的基本假设确实可以成立!好吧,给定一个适当的编译器,使奇怪的空测试......

那么,我们对指针一般还有什么了解......

你要做的是先增加一个指针

  

“一个操作数应该是指向完整对象类型的指针,另一个操作数应该是整数类型。(递增相当于添加1.)”[6.5.6§2]

然后是指针差异

  

“两个操作数都是兼容完整对象类型的限定或非限定版本的指针”[6.5.6§3]

好的,它们是(好吧,假设类型是完整的对象类型)。但是语义呢?

  

“出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型“。 [6.5.6§7]

这实际上有点问题:空指针不需要指向实际对象! (否则你可以安全地取消引用它...)因此,增加它或从另一个指针中减去它是UB!

总结:0未指向某个对象,因此您的问题的答案为否。

答案 3 :(得分:0)

严格符合标准的编译器可以拒绝这一点,或者返回一些废话。在“典型”机器和指针上具有相同的大小,并且向指针投射整数只是采用该位模式并将其视为指针。有些机器中的单词包含额外的数据(类型可能是权限位)。对于某些对象可能禁止某些地址(即,没有任何地址可以具有地址0),等等。虽然可以保证sizeof(char) == 1,例如Crays一个字符实际上是32位。

此外,C标准保证sizeof(expression)中的表达式根本不进行评估,仅采用其类型。即,^ sizeof(x ++)doesn't increment x`。