运算符地址和右值
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];
arr
和 &arr[0]
具有类型 指向 int 的指针 (int *
)
&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
下面有代码部分,我对此有疑问。
虽然我预料到编译器错误,但这个程序的输出是 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];
arr
和&arr[0]
具有类型 指向 int 的指针 (int *
)&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