stackoverflow热门问题(一)-为什么数组的a[5] == 5[a]?

stackoverflow热门问题目录

如果翻译有问题,麻烦评论提出。

新栏目,本来博客刚开的时候是准备把自己的文章写个中英文版的,来提升下英语水平,结果写着写着就偷懒了…
所以开个新栏目,每周六更新。

为什么数组的a[5] == 5[a]?

  • Dinah 提问:
  • 17个回答:
    1. mmx – 1982位用户认为有用:
      • C标准对于[]操作符的定义如下:
      • a[b] == *(a + b)
      • 因此,a[5]可看做:
      • *(a + 5)
      • 同样,5[a]可看做:
      • *(5 + a)
      • a是指向数组第一个元素的指针。a[5]是a后面第五个元素的值,这与*(a + 5)相同,用小学数学就能判断他们相等(加法交换律)。
    2. David Thornley – 292位用户认为有用:
      • 因为数组的访问是根据指针定义的,a[i]被定义为*(a + i),这是可交换的。
    3. Keith Thompson – 242位用户认为有用:
      • 我认为有些东西被其他回答者忽略了。
      • 没错,p[i]根据定义等同于*(p + i),也等价于*(i + p)(根据加法交换律),即等价于i[p](由p[]操作符定义)。
      • (并且在array[i]中,数组名被隐式转换成指向数组第一个元素的指针。)
      • 但在这种情况下,加法的可交换性并不明显。
      • 当两个操作数是同类型,或者由不同的数字类型转换的同类型,交换性最有意义:x + y == y + x
      • 但这种情况下,我们讨论的是指针算法,只有一个操作数是指针,而另一个操作数是整数。(整数 + 整数是不同的操作,且指针 + 指针是无意义的)
      • C标准对于+操作符的描述如下(N1570 6.5.6):
        • 对于加法,要么两个操作数都有算数类型,要么一个操作数是指向完整对象类型的指针且另一个是整型。
      • 换种简单的说法:
        • 对于加法,要么两个操作数都有算数类型,要么左操作数是指向完整对象类型的指针且右操作数是整型。
      • 在这种情况下,i + pi[p]都是不合法的。
      • 在C++的术语中,我们有两个被重载的+运算符,大致描述如下:
      • pointer operator+(pointer p, integer i);
      • 以及
      • pointer operator+(integer i, pointer p);
      • 只有第一个是真正必要的。
      • 那么为什么是这样?
      • C++从C继承了这个定义,而C是从B继承的(数组索引的可交换性在1972年的 Users’ Reference to B被明确提到),B又是从BCPL(1967年的手册)继承的,那么BCPL又是从哪个更早的语言继承的?(CPL还是Algol?)
      • 所以数组索引定义为加法,甚至这个指针或整数的加法都是可交换的想法,得追溯至很久以前作为C祖辈的语言了。
      • 这些语言都比现代C语言更弱类型。尤其是指针与整数的区别常被忽略(在unsigned关键字被添加前,早期C的程序员有时使用指针作为无符号整型)。因为操作数都是不同类型的,所以这些语言的设计者从未考虑过将加法设置成不可交换。如果用户想要添加两个东西,无论这些东西是整型,指针或者其它东西,编程语言都不会阻止它。
      • 这些年来,任何对这规则的改变都会破坏现有代码(尽管1989年的ANSI C标准可能是一个很好的机会)。
      • 让C或者C++将指针放在左边,将整型放在右边的改变,可能会破坏一些现有代码,但不会丧失其可读性。
      • 所以现在我们使用arr[3]与3[arr]来表示同一个东西,尽管后一种形式不能出现在 IOCCC之外。

With arrays, why is it the case that a[5] == 5[a]?

  • Dinah 提问:
    • As Joel points out in Stack Overflow podcast #34, in C Programming Language (aka: K & R), there is mention of this property of arrays in C: a[5] == 5[a]
    • Joel says that it’s because of pointer arithmetic but I still don’t understand. Why does a[5] == 5[a]?
      • Joel说,这是指针算法,但我依然不能理解,为什么a[5] == 5[a]?
      • arithmetic: n.算法
  • 17个回答:
    1. mmx – 1982位用户认为有用:
      • The C standard defines the [] operator as follows:
        • C标准对于[]操作符的定义如下:
      • a[b] == *(a + b)
      • Therefore a[5] will evaluate to:
        • 因此,a[5]可看做:
      • *(a + 5)
      • and 5[a] will evaluate to:
        • 同样,5[a]可看做:
      • *(5 + a)
      • a is a pointer to the first element of the array. a[5] is the value that’s 5 elements further from a, which is the same as *(a + 5), and from elementary school math we know those are equal (addition is commutative).
        • a是指向数组第一个元素的指针。a[5]是a后面第五个元素的值,这与*(a + 5)相同,用小学数学就能判断他们相等(加法交换律)。
        • commutative: adj. 可交换的
    2. David Thornley – 292位用户认为有用:
      • Because array access is defined in terms of pointers. a[i] is defined to mean *(a + i), which is commutative.
        • 因为数组的访问是根据指针定义的,a[i]被定义为*(a + i),这是可交换的。
    3. Keith Thompson – 242位用户觉得有用:
      • I think something is being missed by the other answers.
        • 我认为有些东西被其他回答者忽略了。
      • Yes, p[i] is by definition equivalent to *(p+i), which (because addition is commutative) is equivalent to *(i+p), which (again, by the definition of the [] operator) is equivalent to i[p].
        • 没错,p[i]根据定义等同于*(p + i),也等价于*(i + p)(根据加法交换律),即等价于i[p](由p[]操作符定义)。
      • (And in array[i], the array name is implicitly converted to a pointer to the array’s first element.)
        • (并且在array[i]中,数组名被隐式转换成指向数组第一个元素的指针。)
      • But the commutativity of addition is not all that obvious in this case.
        • 但在这种情况下,加法的可交换性并不明显。
      • When both operands are of the same type, or even of different numeric types that are promoted to a common type, commutativity makes perfect sense: x + y == y + x.
        • 当两个操作数是同类型,或者由不同的数字类型转换的同类型,交换性最有意义:x + y == y + x
      • But in this case we’re talking specifically about pointer arithmetic, where one operand is a pointer and the other is an integer. (Integer + integer is a different operation, and pointer + pointer is nonsense.)
        • 但这种情况下,我们讨论的是指针算法,只有一个操作数是指针,而另一个操作数是整数。(整数 + 整数是不同的操作,且指针 + 指针是无意义的)
      • The C standard’s description of the + operator (N1570 6.5.6) says:
        • C标准对于+操作符的描述如下(N1570 6.5.6):
        • For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.
          • 对于加法,要么两个操作数都有算数类型,要么一个操作数是指向完整对象类型的指针且另一个是整型。
      • It could just as easily have said:
        • 换种简单的说法:
        • For addition, either both operands shall have arithmetic type, or the left operand shall be a pointer to a complete object type and the right operand shall have integer type.
          • 对于加法,要么两个操作数都有算数类型,要么左操作数是指向完整对象类型的指针且右操作数是整型。
      • in which case both i + p and i[p] would be illegal.
        • 在这种情况下,i + pi[p]都是不合法的。
      • In C++ terms, we really have two sets of overloaded + operators, which can be loosely described as:
        • 在C++的术语中,我们有两个被重载的+运算符,大致描述如下:
      • pointer operator+(pointer p, integer i);
      • and
        • 以及
      • pointer operator+(integer i, pointer p);
      • of which only the first is really necessary.
        • 只有第一个是真正必要的。
      • So why is it this way?
        • 那么为什么是这样?
      • C++ inherited this definition from C, which got it from B (the commutativity of array indexing is explicitly mentioned in the 1972 Users’ Reference to B), which got it from BCPL (manual dated 1967), which may well have gotten it from even earlier languages (CPL? Algol?).
        • C++从C继承了这个定义,而C是从B继承的(数组索引的可交换性在1972年的 Users’ Reference to B被明确提到),B又是从BCPL(1967年的手册)继承的,那么BCPL又是从哪个更早的语言继承的?(CPL还是Algol?)
      • So the idea that array indexing is defined in terms of addition, and that addition, even of a pointer and an integer, is commutative, goes back many decades, to C’s ancestor languages.
        • 所以数组索引定义为加法,甚至这个指针或整数的加法都是可交换的想法,得追溯至很久以前作为C祖辈的语言了。
      • Those languages were much less strongly typed than modern C is. In particular, the distinction between pointers and integers was often ignored. (Early C programmers sometimes used pointers as unsigned integers, before the unsigned keyword was added to the language.) So the idea of making addition non-commutative because the operands are of different types probably wouldn’t have occurred to the designers of those languages. If a user wanted to add two “things”, whether those “things” are integers, pointers, or something else, it wasn’t up to the language to prevent it.
        • 这些语言都比现代C语言更弱类型。尤其是指针与整数的区别常被忽略(在unsigned关键字被添加前,早期C的程序员有时使用指针作为无符号整型)。因为操作数都是不同类型的,所以这些语言的设计者从未考虑过将加法设置成不可交换。如果用户想要添加两个东西,无论这些东西是整型,指针或者其它东西,编程语言都不会阻止它。
      • And over the years, any change to that rule would have broken existing code (though the 1989 ANSI C standard might have been a good opportunity).
        • 这些年来,任何对这规则的改变都会破坏现有代码(尽管1989年的ANSI C标准可能是一个很好的机会)。
      • Changing C and/or C++ to require putting the pointer on the left and the integer on the right might break some existing code, but there would be no loss of real expressive power.
        • 让C或者C++将指针放在左边,将整型放在右边的改变,可能会破坏一些现有代码,但不会丧失其可读性。
      • So now we have arr[3] and 3[arr] meaning exactly the same thing, though the latter form should never appear outside the IOCCC.
        • 所以现在我们使用arr[3]与3[arr]来表示同一个东西,尽管后一种形式不能出现在 IOCCC之外。

You may also like...

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注