如何计算两个地址之间的距离?

时间:2018-04-09 19:25:27

标签: c pointers memory byte sizeof

我想计算两个地址之间的字节数。

uint32_t length = &b - &a;

enter image description here

当a和b为uint32_t时,长度为1。

uint32_t a, b;
uint32_t length = &b - &a;  // length is one

当a和b为uint8_t时,长度为4。

uint8_t a, b;
uint32_t length = &b - &a;  // length is four

因此,计算是a和b之间的uint32_t或uint8_t的数量,而不是我错误预期的地址之间的数学差异。

我的问题:C语言的哪一部分包括地址计算?有人可以引用讨论该主题的规范中的位置吗?

3 个答案:

答案 0 :(得分:3)

指针减法在C standard

的第6.5.6节中介绍
  

3 对于减法,以下之一应保留:

     
      
  • 两个操作数都有算术类型;
  •   
  • 两个操作数都指向兼容的完整对象类型的限定或非限定版本;
  •   
  • 左操作数是指向完整对象类型的指针,右操作数是整数类型。
  •   
     

...

     

9 当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组最后一个元素的元素   宾语;结果是两者下标的差异   数组元素。结果的大小是实现定义的,和   它的类型(有符号整数类型)是在ptrdiff_t中定义的    头。如果结果在对象中无法表示   该类型,行为未定义。换句话说,如果   表达式P和Q分别指向第i和第j个元素   对于数组对象,表达式(P) - (Q)具有提供的值i-j   该值适合ptrdiff_t类型的对象。而且,如果   表达式P指向数组对象的元素或一个元素   超过数组对象的最后一个元素,表达式Q指向   到同一个数组对象的最后一个元素,表达式   ((Q)+1) - (P)具有与((Q) - (P))+ 1相同的值和 - ((P) - ((Q)+1)),   如果表达式P指向过去的一个,则其值为零   数组对象的元素,即使表达式(Q)+1没有   指向数组对象的元素。

所以区别在于两者之间的元素的数量,而不是字节数。

请注意,这只允许减去同一数组的两个元素之间的指针。所以这是合法的:

uint32_t a[5];
uint32_t len = &a[1] - &a[0];

但这不是:

uint32_t a, b
uint32_t len = &b - &a;

答案 1 :(得分:1)

如果指针具有不同的类型或不指向相同的存储块(即表或以其他方式分配),则不允许在符合标准的C指针算术中使用

。否则就是UB

但是如果变量位于相同的连续地址空间中 - 例如在ARM中,如果指针具有相同的类型或者将它们转换为相同的类型,则将定义此算法的结果。

这不是符合C标准的代码

#include <stdio.h>
#include <stdint.h>


uint64_t c;
uint64_t d;
uint16_t e;
uint8_t f;


int main(void)
{   uint32_t a,b;
    printf("%lld\n", (long long)((uint8_t *)&b - (uint8_t *)&a));
    printf("%lld\n", (long long)((uint8_t *)&c - (uint8_t *)&a));
    printf("%lld\n", (long long)((uint8_t *)&d - (uint8_t *)&c));
    printf("%lld\n", (long long)((uint8_t *)&e - (uint8_t *)&d));
    printf("%lld\n", (long long)((uint8_t *)&f - (uint8_t *)&c));
}

将打印的内容是100%直至实施。一些结果可能有另一种意义。

这种算法在嵌入式开发中使用,例如通过在链接器脚本中定义符号(例如bss的开始和bss的结尾),然后这些符号(实际上是它们的地址)用于执行诸如归零之类的操作bss或初始化数据段

你可以在Linux机器上试试: https://ideone.com/dm0R5M

答案 2 :(得分:0)

  

我想计算两个地址之间的字节数。

如果地址在同一个数组中,代码可以减去指针以获得差异中元素数量的计数。然后乘以类型的大小来报告“字节”的数量。

ptrdiff_t diff = &a[some_index] - &a[some__other_index];
diff *= sizeof a[0];
printf("Diff %td\n", diff);

如果不知道2个对象的地址在同一个数组中,代码可以仔细减去,但根据内存模型,差异可能代表也可能不代表“字节”差异。 IAC,下面避免了未定义的行为

#include <inttypes.h>
#include <stdio.h>

void *va = &a;
void *vb = &b;
// optional types
uintptr_t ua = (uintptr_t)va;
uintptr_t ub = (uintptr_t)vb;
uintptr_t diff = ua > ub ? ua - ub : ub - ua;
printf("Maybe byte difference of %" PRIuPTR "\n", diff);