如何计算两个地址之间的距离?
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);
我想计算两个地址之间的字节数。
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;
在符合标准的 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);