指针算法 - 编译器如何确定要递增的字节数?
Pointer arithmetic - how does the compiler determine the number of bytes to increment?
考虑以下代码。
#include <iostream>
int main(){
int a[] = {1,2,3,4,5};
int b = 5;
std::cout << a[b] << std::endl;
std::cout << b[a] << std::endl;
}
我理解 a[b]
和 b[a]
是相同的,正如标准所规定的那样:
Except where it has been declared for a class (13.5.5), the subscript
operator [] is interpreted in such a way that E1[E2] is identical to
*((E1)+(E2)). Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member
of E1. Therefore, despite its asymmetric appearance, subscripting is a
commutative operation.
不过,我还是不太明白。编译器确实以字节为单位进行寻址运算。由于一个int占用4个字节,所以a[b]
和b[a]
都会被翻译成*(a + b * 4)
。我的问题是:编译器如何确定正确的翻译是 *(a + b * 4)
,而不是 *(b + a * 4)
?当编译器得到 E1[E2]
形式的表达式时,编译器可以将其翻译成 *(E1 + E2 * 4)
或 *(E2 + E1 * 4)
- 编译器如何知道哪个是正确的选择?
决定因素类型不是对象的大小。它是对象的实际、完整类型。
编译器知道每个对象的实际类型。编译器不仅知道 a
是四个字节(或者在 64 位系统上是八个字节),而且它是一个指针并且 b
是一个整数类型。这是 C++ 的一个基本方面:每个对象的类型在编译时是并且必须是已知的。
因此,当将指针类型添加到整数类型时,整数值会乘以所指向类型的大小。哪个在 +
运算符的左侧和右侧并不重要。如果一个操作数是指针,而另一个是整数类型,这就是 C++ 中发生的情况。
想象一种 C±± 语言,它就像 C++,只是它没有任何数组索引的概念,也没有下标 operator []
。不过,所有其他 C++ 规则和定义仍然适用。
Except where it has been declared for a class (13.5.5), the subscript
operator [] is interpreted in such a way that E1[E2] is identical to
*((E1)+(E2)).
这里C++标准所说的可以粗略地理解为:C++编译器首先将所有下标表达式E1[E2]
翻译成*((E1)+(E2))
。结果是有效的C±±码,
然后根据C±±规则进一步评估。
这意味着 a[b]
和 b[a]
分别转换为 *(a + b)
和 *(b + a)
,它们是相同的,因为加法在 C++ 中是可交换的(因此 C± ±).
考虑以下代码。
#include <iostream>
int main(){
int a[] = {1,2,3,4,5};
int b = 5;
std::cout << a[b] << std::endl;
std::cout << b[a] << std::endl;
}
我理解 a[b]
和 b[a]
是相同的,正如标准所规定的那样:
Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)). Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its asymmetric appearance, subscripting is a commutative operation.
不过,我还是不太明白。编译器确实以字节为单位进行寻址运算。由于一个int占用4个字节,所以a[b]
和b[a]
都会被翻译成*(a + b * 4)
。我的问题是:编译器如何确定正确的翻译是 *(a + b * 4)
,而不是 *(b + a * 4)
?当编译器得到 E1[E2]
形式的表达式时,编译器可以将其翻译成 *(E1 + E2 * 4)
或 *(E2 + E1 * 4)
- 编译器如何知道哪个是正确的选择?
决定因素类型不是对象的大小。它是对象的实际、完整类型。
编译器知道每个对象的实际类型。编译器不仅知道 a
是四个字节(或者在 64 位系统上是八个字节),而且它是一个指针并且 b
是一个整数类型。这是 C++ 的一个基本方面:每个对象的类型在编译时是并且必须是已知的。
因此,当将指针类型添加到整数类型时,整数值会乘以所指向类型的大小。哪个在 +
运算符的左侧和右侧并不重要。如果一个操作数是指针,而另一个是整数类型,这就是 C++ 中发生的情况。
想象一种 C±± 语言,它就像 C++,只是它没有任何数组索引的概念,也没有下标 operator []
。不过,所有其他 C++ 规则和定义仍然适用。
Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)).
这里C++标准所说的可以粗略地理解为:C++编译器首先将所有下标表达式E1[E2]
翻译成*((E1)+(E2))
。结果是有效的C±±码,
然后根据C±±规则进一步评估。
这意味着 a[b]
和 b[a]
分别转换为 *(a + b)
和 *(b + a)
,它们是相同的,因为加法在 C++ 中是可交换的(因此 C± ±).