C++ 从数组定义行为中间的指针进行负索引?

Huy*_* Le 9 c++ arrays string indexing undefined-behavior

#include <iostream>
using namespace std;

const int BUFSIZE = 1 << 20;
char padded_buffer[64 + BUFSIZE + 64];
char* buffer = padded_buffer + 64;

int main()
{
    buffer[-1] = '?';
    // is that always equivalent to padded_buffer[63] = '?' ?
    cout << padded_buffer[63] << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我有一段像上面这样的代码。基本上,由于某些原因,我需要“隔离”阵列的两侧。

但我想知道上面的语法是否安全?我知道负索引通常是未定义的行为,但是这种情况又如何呢?

for*_*818 10

来自https://eel.is/c++draft/expr.sub#2

该表达式E1[E2](根据定义)与 相同*((E1)+(E2)),但在数组操作数的情况下,如果该操作数是左值,则结果是左值,否则结果是 xvalue。

只要您仅到达指向同一数组中元素的指针,就可以定义指针算术。

不存在未定义的行为。buffer[-1]只是*(padded_buffer + 64 -1)


它有点基于意见,但buffer[-1]看起来很奇怪。恕我直言,它混淆了这样一个事实:它buffer不是一个数组,而是一个指向实际数组中间元素的指针。如果您想将某些内容分配给数组的第 63 个元素padded_buffer,则只需执行以下操作:padded_buffer[63] = '?';

在评论中,我建议将数组包装在具有重载的自定义类型中operator[],但这并不能解决外观奇怪的问题x[-1]。也许我宁愿让索引转换在调用代码中直接可见,以便将padded_array[ transform_index(-1) ].

  • 这个答案当然是正确的,但最后两段是基于观点的。答案很简单:“是的,行为是明确定义的”;当然,在某些情况下,负索引是很自然的。例如,考虑用作堆栈的数组,其中“top”指向下一个可用槽。在我看来,“top[-2]”是引用倒数第二个堆栈元素的完全合理的方式(假设您知道堆栈上至少有两个元素)。您可以自由地不同意这种风格,因为这是一个意见问题。 (2认同)