运算符地址和右值

Address of operator and r-value

下面有代码部分,我对此有疑问。

虽然我预料到编译器错误,但这个程序的输出是 2 5。从我的角度来看,&a+1 语句应该导致编译器错误。原因是 (a + 1) 由于运算符优先级而首先执行,并且 (a+1) 语句指向数组中的 2 。然后,运算符 (&) 的地址有 (a + 1) 个操作数,但 (a + 1) 是一个右值表达式,因此 &a+1 应该会导致编译器错误。

我有什么错?

int main()
{

    int a[5] = {1,2,3,4,5};

    int *ptr = (int*)(&a+1);

    printf("%d %d", *(a+1), *(ptr-1));

    return 0;
}

数组衰减为指针。这些指针中的任何一个都引用内存中的相同地址。区别在于这个指针的类型。

int arr[5];
  1. arr&arr[0] 具有类型 指向 int 的指针 (int *)
  2. &arr 的类型为 指向五个元素整数数组的指针 ( int (*)[5])

Then, the address of operator (&) has (a + 1) operand but (a + 1) is an r-value expression and therefore &a+1 should cause a compiler error.

不,& 运算符应用于 a 而不是 a + 1&a + 1 === (&a) + 1

在您的例子中,&a 是指向 5 个 int 元素的指针。 &a + 1 引用 下一个包含 5 个 int 元素的数组 ,而不是数组 a 的下一个元素。然后将此值分配给 int * 指针并取消引用先前的 int 值。由于指针 ptr 引用元素 past 数组的最后一个元素 a 因此前一个元素是 last 数组的元素 a

您似乎对实际的运算符优先级感到困惑。

一元 address-of 运算符 & 比二元加法运算符 + 具有 更高 的优先级。所以在表达式 &a+1 中,address-of 运算符首先应用于 a 这是有效的,因为 a 是一个左值,然后将 1 添加到结果中。

实际的优先级规则来自 C 标准中的语法,尽管新手很难推断出它们的实际含义。 可以在此处找到运算符优先级的良好参考:

https://en.cppreference.com/w/c/language/operator_precedence

从这个图表可以看出,二元按位与运算符&的优先级确实低于二元加法运算符+,但一元address-of运算符& 具有更高的优先级。

这里你定义对象 a 为一个包含 5 个整数的数组。

    int a[5] = {1,2,3,4,5};

在这里,您使用 &a,这意味着,一个指向对象的指针,该对象是一个包含 5 个整数的数组 -- sizeof(a)=5*sizeof(int).

对象 &a+1 也是一个指向 5 个整数数组的指针(如果你这样做 (&a+1)-a 你将得到 sizeof(a)),即 5*sizeof(int)。因此,ptr 将指向 a 之外的 5 个整数(与 a[0] 相同)。

    int *ptr = (int*)(&a+1);

接下来,您访问 *(ptr-1),但这次指针算法将仅从 ptr 中减去 sizeof(int),因为 ptr 的类型为 pointer to int——您将访问地址 ptr[-1] 处的整数,它落在第一个包含五个元素的数组 (&a)[0] 内,它指向最后一个整数。

    printf("%d %d", *(a+1), *(ptr-1));

*(a+1) 很简单,就是 a[1],整数类型。

     &(a[1])       ptr-1 ptr
     |              |    |
     V              V    V
+----+----+----+----+----+----+----+----+----+----+
|    |    |    |    |    |    |    |    |    |    |
+----+----+----+----+----+----+----+----+----+----+
^                        ^                        ^
+------------------------+------------------------+
|                        |                        |
&a                       &a+1                     &a+2