在编译时强制执行静态存储

Enforce Static Storage at Compile-time

本文关键字:静态 存储 强制执行 编译      更新时间:2023-10-16

我有一个结构,我想在上面强制执行静态存储。这是DSP上的矢量类型,意外地在堆栈上声明它对用户来说是一个常见的错误,会导致堆栈溢出、性能问题或两者兼而有之。据我所知,这是不可能的,但我很好奇是否有其他人知道得更好。

示例用例:

static Vector64 v1;  // OK
static Vector64 v2;  // OK
static Vector64 result; // OK
result = v1 * v2; // OK
Vector64 v3; // I would like this to give a compile-time error
Vector64 v4;
result = v3 * v4;

我的编译器是Clang/LLVM3.2,编译器特定的属性是公平的。

由于C没有类,我几乎排除了这种可能性。

通常,在C++中,当您定义一个类时,您无法控制该类型的对象是在static、堆栈上、堆上、const还是不在const、数组中定义,还是在另一个类的成员中定义。这些选项由类的用户决定。

有一些技巧可以让它远离堆(例如玩operator new),或者只在堆上(例如使用生成器模式),但这不是你想要的

我很想看看这是怎么可能的,但在这个时候之前,我敢肯定你做不到。

如果您愿意接受运行时错误并深入实现,并且如果您的DSP有合适的地址布局,您可以简单地在Vector64的默认构造函数中插入this的位置检查。

如果你提前知道地址空间,最安全的事情(从语言角度来看)就是简单地比较堆栈的绝对位置。

struct Vector64 {
Vector64() { assert( reinterpret_cast<uintptr_t>(this) < STACK_START ); }
};

风险更大但更灵活的定义可能是这样的:

__attribute__((noinline)) Vector64() {
int test;
assert( less<void*>()(this, &test) );
}

其中需要__attribute__((noinline))来防止clang在Vector64对象之前对test的分配进行排序(或者简单地在其他地方定义它)。从好的方面来看,重新排序优化不会导致此断言抛出误报,只会无声地失败。std::less在这里也很重要,因为与<不同,它明确允许在不同对象的地址之间进行比较。

这种方法非常糟糕,但通过干扰构建,这是在运行时通过确保不再构建堆栈来防止堆栈溢出的最佳机会。

如果你在C上编程,你会遇到问题。有了C++,它应该可以工作了。我从来没有用过那个编译器,但这两种语言在这方面有很大的不同。检查编译器。