在 C++ 中访问数组负索引处的内存不会返回垃圾

Accessing memory at negative indexes of array in C++ does not return garbage

本文关键字:内存 返回 C++ 访问 数组 索引      更新时间:2023-10-16

我编写了以下程序来搜索给定字符串数组中的特定字符串。我在搜索函数中犯了一个错误,写了 i-- 而不是 i++。

#include <iostream>
#include <string>
using namespace std;
int search(string S[], int pos, string s)
{
for(int i=0; i<pos; i--) {
cout << i << " : " << S[i] << "n";
if (S[i] == s) {
cout << "Inside Return ->n";
cout << i << " / " << S[i] << " / " << s << "n";
return i;
}
}
return -1;
}
int main()
{
string S[] = {"abc", "def", "pqr", "xyz"};
string s = "def";
cout << search(S,2,s) << "n";
return 0;
}

从逻辑上讲,循环是一个无限循环,不应该停止,但我观察到的是每次搜索的 if 条件都为真,并且函数返回 -1。

我打印了这些值,并注意到 S[-1] 的值始终与传递给函数(要搜索的字符串(的第三个参数相同,因此循环每次都返回 -1。

这是 g++ 正在做的事情,还是与为函数的形式参数分配内存的方式有关?

输出上述代码 -

0 : abc
-1 : def
Inside Return ->
-1 / def / def

PS - 我正在使用 g++ (Ubuntu 7.3.0-27ubuntu1~18.04( 7.3.0

编辑 - 我知道 g++ 不检查边界,但我对 S[-1] 的值始终与 s 相同这一事实很感兴趣。我想知道是否有任何可能的理论

越界访问是未定义的行为。

未定义的行为不是"垃圾"或"段错误",它实际上是任何东西。 读取可能会进行时间旅行,并使程序早期的代码行为不同。 程序的行为,从头到尾,每当任何地方发生任何未定义的行为时,它完全不受C++标准的规定。

在这种情况下,朴素汇编和 ABI 会告诉您,运行时"堆栈"上的参数位于函数参数等内容旁边。

因此,将代码天真地重写为汇编会导致从参数读取到函数的负索引。

但是,将程序作为机器代码的无数完全无害,常见和安全的替代解释,从内联开始,远离那里,使这种情况不会发生。

在没有 LTO 或动态库边界的情况下进行编译时,您可以对编译器发布的 ABI 将用于进行调用有少量的信心;其他地方的任何假设都是危险的糟糕。 如果你在没有 LTO 的情况下进行编译并依赖它,这意味着你必须从现在开始直到永远审核代码的每个构建,否则冒着错误出现的风险,从现在开始很久没有明显原因。