指针算术(使用强制转换的指针减法)

时间:2014-06-07 15:01:13

标签: c++ c pointers pointer-arithmetic

为什么执行结束时的j为“1”? 在64位Unix计算机上使用以下标志 gcc -m32 xxx.c 进行编译。

#include <stdio.h>
int main(int argc, char **argv)
{
  int  *q = (int *)2;
  char *r = (char *)1;
  int j;

  q++; 
  r++;

  j = (int *)q - (int *)r;

  printf("j = %d\n", j);
  return 0; 
}

代码仅用于学术目的! ;)

2 个答案:

答案 0 :(得分:4)

首先,从理论上讲,这是所有未定义的行为,因为您使用指针未分配内存,比较不属于同一数组的内容等。

现在,把它放在一边,一旦你清楚了指针运算的机制,它就很容易了:

int  *q = (int *)2;
char *r = (char *)1;
int j;
// a pointer is incremented in steps of the size of its "base type"; this
// allows to move to the next element if you are pointing inside an array
q++;   // q=(int*)(2+sizeof(int))=(int *)6
r++;   // r=(char *(1+sizeof(char))=(int *)2;

// again, the difference between two pointers is computed in units of the
// base type; in an array, this gives you how many places are two elements
// apart
j = (int *)q - (int *)r; // (6-2)/sizeof(int)=1

(此处sizeof(int)为4,因为您使用gcc和-m32进行了编译,而根据sizeof(char)的定义,sizeof为1

答案 1 :(得分:1)

  

注意:您正在调用未定义的行为,没有任何说明int的对齐方式为2或更少;也不是同一个数组的qr成员,也不是同一个对象..你永远不应该在你的代码片段中做你正在做的事情。


忽略明显的未定义行为

一个人不应该轻易采取未定义的行为,你的代码的结果是高度特定于实现的,并且几乎可以做任何事情。但理论上,代码将被解释如下所述,但没有这样的保证。


  • j将是qr之间的距离(均被解释为int*)。

  • 增加指向int的指针会将sizeof(int)个字节向前移动,而将指针递增到char会将其sizeof(char)字节向前移动。

  • 从另一个指针中减去一个指针会产生它们之间的元素的数量,而不是字节数。


一些假设和详细描述

假设底层实现具有sizeof(int) = 4,我们将使用以下伪代码:

int_ptr  q = 2
char_ptr r = 1

/* ++q -> */ value_of(q) += 4;   // sizeof(int) = 4,  value_of(q) = 6
/* ++r -> */ value_of(r) += 1;   // sizeof(char) = 1, value_of(r) = 2

int j = int_ptr(q) - int_ptr(r); // j = 1
                                 // (value_of(q) - value_of(r))/sizeof(int)

答案j = 1