【问题标题】:Class member access through out of bounds access to array member通过对数组成员的越界访问来访问类成员
【发布时间】:2020-10-07 14:16:36
【问题描述】:

我见过一个非常有经验的程序员做这样的事情:

#include <iostream>
#include <string>
using namespace std;
typedef int BOOL;

BOOL is_max(int a) {
    return a&3;
}

class Foo
{
    public:
    inline Foo()    {}
    inline ~Foo()   {}

    int     min[3];
    int     max[3];
};

int main()
{   
    Foo foo = Foo();
    for (int i=0; i<3; i++) {
        foo.min[i] = i;
        foo.max[i] = i+3;
    }
    
    BOOL b = is_max(75); // b==3
    
    // Print out foo.max[1] (which is foo.min[4])
    cout << foo.min[1+b] << endl;
}

这是代码中计算量非常大的部分。所以我想它确实比使用 if 条件创建分支要快。由于两个数组(max 和 min)都是 int 类型并且在类定义中是连续的,因此这应该始终有效。

是否有理由避免这种方法?我知道这对于代码的可读性和可维护性可能不是最好的(例如,如果有人会在错误的位置添加第三个成员在类定义中,即在min 和max 之间)。可能会有更好的方法

int[6] extrema;

除此之外,这种方法还有其他缺点吗?这会以某种方式导致过早终止/分段错误吗?

【问题讨论】:

  • 编译器可以在成员之间添加任意填充。
  • 除此之外,我认为使用BOOL 作为整数类型看起来很混乱,应该避免。
  • 你不应该这样做,因为它在技术上是越界访问和未定义的行为。
  • int extrema[6]; int* min = &amp;extrema[0]; int* max = &amp;extrema[3];?
  • @David 这是一种有时在没有布尔类型的旧 C 中看到的方法。当未定义的行为可能不被视为大事时,也可能已经编写了较旧的代码库。可能是因为优化范围更窄?

标签: c++ arrays pointers data-structures


【解决方案1】:

有两个问题,首先,如果b 大于1 是越界访问,这是未定义的行为。

另一个问题是,编译器只看到foo.max[i] = i+3;,但在您的代码中没有任何迹象表明max 在循环之后的任何时候都被使用。所以从优化器的角度来看,由于访问max 槽min 是无效的,它可以假设循环中的foo.max[i] = i+3; 是无用的,理论上可以将其优化掉。

基于对 gcc 的编译输出的简短了解,开启了优化,这似乎确实如此。

因此,即使不涉及任何未知的填充,并且您可以确定内存布局,它仍然绝对是您绝对不能做的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多