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

C 如何计算两个地址之间的距离?,c,pointers,memory,byte,sizeof,C,Pointers,Memory,Byte,Sizeof,我想计算两个地址之间的字节数 uint32_t length = &b - &a; 当a和b为uint32时,长度为1 uint32_t a, b; uint32_t length = &b - &a; // length is one 当a和b为uint8时,长度为4 uint8_t a, b; uint32_t length = &b - &a; // length is four 因此,计算是a和b之间的uint32_t或uint

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

uint32_t length = &b - &a;

当a和b为uint32时,长度为1

uint32_t a, b;
uint32_t length = &b - &a;  // length is one
当a和b为uint8时,长度为4

uint8_t a, b;
uint32_t length = &b - &a;  // length is four
因此,计算是a和b之间的uint32_t或uint8_t的数量,而不是我错误地预期的地址之间的数学差


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

指针减法在本手册第6.5.6节中介绍:

3对于减法,以下其中一项应适用:

  • 两个操作数都具有算术类型
  • 两个操作数都是指向兼容完整对象类型的合格或不合格版本的指针
  • 左操作数是指向完整对象类型的指针,右操作数是整数类型

9减去两个指针时,两个指针都应指向同一数组对象的元素,或指向数组最后一个元素的一个 对象结果是两个的下标不同 数组元素。结果的大小由实现定义,并且 其类型(有符号整数类型)是在 标题。如果结果不能在对象中表示 对于该类型,行为是未定义的。换句话说,如果 表达式P和Q分别指向第i个和第j个元素 对于数组对象,表达式(P)-(Q)的值为i−j提供 该值适合ptrdiff_t类型的对象。此外,如果 表达式P指向数组对象的一个元素或一个 超过数组对象的最后一个元素,表达式Q点 对于同一数组对象的最后一个元素,表达式 ((Q)+1)-(P)与((Q)-(P))+1和as-((P)-(Q)+1)具有相同的值, 如果表达式P指向最后一个点后一个,则其值为零 数组对象的元素,即使表达式(Q)+1没有 指向数组对象的一个元素

因此,两者之间的差异是元素的数量,而不是字节的数量

ptrdiff_t diff = &a[some_index] - &a[some__other_index];
diff *= sizeof a[0];
printf("Diff %td\n", diff);
请注意,这只允许在同一数组的两个元素之间减去指针。所以这是合法的:

uint32_t a[5];
uint32_t len = &a[1] - &a[0];
但这不是:

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

第6.5.6节介绍了指针减法:

3对于减法,以下其中一项应适用:

  • 两个操作数都具有算术类型
  • 两个操作数都是指向兼容完整对象类型的合格或不合格版本的指针
  • 左操作数是指向完整对象类型的指针,右操作数是整数类型

9减去两个指针时,两个指针都应指向同一数组对象的元素,或指向数组最后一个元素的一个 对象结果是两个的下标不同 数组元素。结果的大小由实现定义,并且 其类型(有符号整数类型)是在 标题。如果结果不能在对象中表示 对于该类型,行为是未定义的。换句话说,如果 表达式P和Q分别指向第i个和第j个元素 对于数组对象,表达式(P)-(Q)的值为i−j提供 该值适合ptrdiff_t类型的对象。此外,如果 表达式P指向数组对象的一个元素或一个 超过数组对象的最后一个元素,表达式Q点 对于同一数组对象的最后一个元素,表达式 ((Q)+1)-(P)与((Q)-(P))+1和as-((P)-(Q)+1)具有相同的值, 如果表达式P指向最后一个点后一个,则其值为零 数组对象的元素,即使表达式(Q)+1没有 指向数组对象的一个元素

因此,两者之间的差异是元素的数量,而不是字节的数量

ptrdiff_t diff = &a[some_index] - &a[some__other_index];
diff *= sizeof a[0];
printf("Diff %td\n", diff);
请注意,这只允许在同一数组的两个元素之间减去指针。所以这是合法的:

uint32_t a[5];
uint32_t len = &a[1] - &a[0];
但这不是:

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

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

但是,如果变量位于相同的连续地址空间中——例如,在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));
}
#包括
#包括
uint64_t c;
uint64_t d;
uint16_t e;
uint8_t f;
内部主(空)
{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归零或初始化数据段等操作

您可以在Linux机器上尝试:

如果指针具有不同类型或未指向同一内存块(即表或以其他方式分配),则不允许在标准兼容C中使用指针算术。否则就是UB

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