【问题标题】:C++ array[index] vs index[array] [duplicate]C ++数组[索引]与索引[数组] [重复]
【发布时间】:2010-10-28 16:33:20
【问题描述】:

可能重复:
In C arrays why is this true? a[5] == 5[a]

array[index] 和 index[array] 是编译器特性还是语言特性的可能性。第二个怎么可能?

【问题讨论】:

标签: c++ c arrays


【解决方案1】:

编译器会转

index[array]

进入

*(index + array)

使用正常的语法会变成这样

array[index]

进入

*(array + index)

因此您会看到两个表达式的计算结果相同。这适用于 C 和 C++。

【讨论】:

  • 这种“转换”说明仅在变量之一是指针或数组而另一个是整数类型时才成立,即通常的 C 情况。在 C++ 中,a[b] 失去了对称性,因为 operator[] 可以是重载的成员函数,并且不允许编译器使用 *(a+b) 代替。 *(a+b) 可能有不同的类型和不同的值,或者它可能根本不是一个有效的表达式。
  • +1。凉爽的。从来没有这样想过。
【解决方案2】:

从 C 的早期开始,表达式a[i] 只是将 a[0] 的地址添加到 i(按 a[0] 的大小放大)然后取消引用。事实上,所有这些都是等价的:

a[i]
i[a]
*(a+i)

====

我唯一关心的是实际的取消引用。虽然它们都产生相同的地址,但如果a 和i 的类型不同,则可能需要考虑取消引用。

例如:

    int i = 4;
    long a[9];
    long x = a[i]; //get the long at memory location X.
    long x = i[a]; //get the int at memory location X?

我还没有实际测试过这种行为,但您可能需要注意这一点。如果它确实改变了被取消引用的内容,那么它也可能会导致对象数组出现各种问题。

====

更新:

您可以放心地忽略上面===== 行之间的位。我已经在 Cygwin 下用短和长测试了它,看起来还不错,所以我想我的担心是没有根据的,至少对于基本情况。我仍然不知道更复杂的会发生什么,因为这不是我想做的事情。

【讨论】:

  • 我认为没有什么不同。我的意思是它可以追溯到最早的日子,并不是说它只是在早期那样。
  • 这是错误的。无论哪种方式,编译器都知道将 int 添加到 long*(以任意顺序)会导致 long*,然后将其取消引用为 long。这适用于任何指针类型,包括用户定义的。
  • 方法错误。 @马修?我已经说过我的怀疑是不正确的,标准类型工作正常。至于更复杂的类型,我没有发表评论只是因为它不是我尝试过(或可能会尝试)的任何东西。
  • 为什么在您投票结束时发布此消息? dup 有很多好的答案,但你至少应该做这个 CW。
  • 我早在别人发现骗子之前就发布了这个答案。然后我同意了在我检查了这个骗局后关闭的决定。这不是火箭科学。而且,实际上,人们如何回答问题或是否将问题设为 CW 并不取决于您。这取决于回答者自己。如果这不是一个适合 SO 的问题,我会去 CW(或者更有可能只是留下评论),但这个 是 一个合适的问题,只是重复。
【解决方案3】:

正如 Matthew Wilson 在 Imperfect C++ 中所讨论的,这可用于强制 C++ 中的类型安全,方法是防止在定义下标运算符的类型实例中使用类似于 DIMENSION_OF() 的宏,如下所示:

#define DIMENSION_OF_UNSAFE(x)  (sizeof(x) / sizeof((x)[0]))

#define DIMENSION_OF_SAFER(x)  (sizeof(x) / sizeof(0[(x)]))

int ints[4];

DIMENSION_OF_UNSAFE(ints); // 4
DIMENSION_OF_SAFER(ints); // 4

std::vector v(4);

DIMENSION_OF_UNSAFE(v); // gives impl-defined value; v likely wrong
DIMENSION_OF_SAFER(v); // does not compile

处理指针还有更多内容,但这需要一些额外的模板智能。查看STLSoft 库中STLSOFT_NUM_ELEMENTS() 的实现,并在Imperfect C++ 的第14 章中阅读所有内容。

编辑:一些评论者建议实现不拒绝指针。它确实如此(以及用户定义的类型),如下面的程序所示。您可以通过未注释的第 16 行和第 18 行来验证这一点。(我只是在 Mac/GCC4 上这样做,它拒绝了这两种形式)。

#include <stlsoft/stlsoft.h>
#include <vector>
#include <stdio.h>

int main()
{
    int     ar[1];
    int*    p = ar;
    std::vector<int>        v(1);

    printf("ar: %lu\n", STLSOFT_NUM_ELEMENTS(ar));

//  printf("p: %lu\n", STLSOFT_NUM_ELEMENTS(p));

//  printf("v: %lu\n", STLSOFT_NUM_ELEMENTS(v));

    return 0;
}

【讨论】:

  • 使用模板可以实现更好的“维度”实现: template std::size_t dimension( T[N]& x ) { return N; }。这将比带有数组(尚未衰减为指针)的 sizeof(a)/sizeof(a[0]) 更安全。
  • dribeas:问题在于它不再是编译时表达式。 Wilson 描述的技术说明了一个编译时版本。正如我所说,它在 STLSoft 库中可用。
  • 还有一种方法可以获取编译时表达式:template char (& an_array(T(&)[N]) )[N];这将评估对具有相同大小的 char 数组的引用。像这样使用它: int v[sizeof an_array(another_array)];
  • 请注意,我的宏和 dribea 的宏都与 wilson 的宏不同,当然。我们的将拒绝一个指针。他的人会接受的。因此,这些是不同的用例。
  • tlib,dribeas:你们都错了。请参阅上面的编辑回复。
【解决方案4】:

在 C 和 C++ 中(array 是指针或数组)它是一种语言特性:指针运算。将 a 或 b 为指针的操作 a[b] 转换为指针算术:*(a + b)。由于加法是对称的,因此重新排序不会改变含义。

现在,非指针存在差异。事实上,给定一个带有重载 operator[] 的类型 A,那么 a[4] 是一个有效的方法调用(将调用 A::operator),但相反的甚至不会编译。

【讨论】:

    猜你喜欢
    • 2018-04-20
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    • 2018-12-31
    • 2017-10-27
    • 1970-01-01
    • 2018-10-25
    • 2021-12-09
    相关资源
    最近更新 更多