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

how is distance between two addresses computed?

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

uint32_t length = &b - &a;

当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语言的哪一部分涉及地址的计算?有人可以参考规范中讨论该主题的位置吗?

指针减法在 C standard 的第 6.5.6 节中介绍:

3 For subtraction, one of the following shall hold:

  • both operands have arithmetic type;
  • both operands are pointers to qualified or unqualified versions of compatible complete object types; or
  • the left operand is a pointer to a complete object type and the right operand has integer type.

...

9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object.

所以两者的区别是元素个数,而不是字节数

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

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

但这不是:

uint32_t a, b
uint32_t len = &b - &a;
如果指针具有不同类型或不指向同一内存块(即 table 或以其他方式分配),则

在符合标准的 C 指针算法中是不允许的。否则就是UB

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

这不是符合 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

I would like to compute the number of bytes between two addresses.

如果地址在同一个数组中,代码可以减去指针来计算差值中的元素数。然后乘以类型的大小得到"bytes".

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

如果不知道 2 个对象的地址在同一个数组中,代码可以小心地减去,但根据内存模型,差异可能代表也可能不代表 "byte" 差异。 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);