【问题标题】:Is it possible to change the allocation area of automatic variables in C/C++?是否可以在 C/C++ 中更改自动变量的分配区域?
【发布时间】:2013-02-05 05:05:53
【问题描述】:

这是一个 C 和 C++ 的理论问题。

我有一个 4x4 矩阵类型,其定义非常简单:

typedef float   Matrix44[16];

我也有很多以Matrix44为参数的方法,例如:

bool matrixIsIdentity(Matrix44 m);

我还有一个自定义的内存分配方案,在堆上预分配大面积的内存,然后我手动管理预取内存上的分配。因此,我已经用我自己的实现替换/重载了malloc/new。问题是,自定义mallocnew 本质上都返回一个指针,而不是一个对象。

通常,我会简单地执行以下操作:

   // Method 1
1] Matrix44 mat = { ... };
2] bool res = matrixIsIdentity(mat);

但是,第 1 行在堆栈上分配了mat,而不是我希望的自定义​​内存区域。另一种选择是:

    // Method 2
1]  Matrix44 *mmat = myMalloc(...);
1a] Matrix44 *nmat = new ...
2]  bool res = matrixIsIdentity(*mat);

这里的问题是我将不得不在我的代码中乱扔解引用运算符。现在一种选择是重写所有方法以采用Matrix44*,但是,由于这是理论上的,我想假设这不是一种选择。

因此我的问题变成了:有没有办法像 Method 1 Line 1 那样在 C 和/或 C++ 中声明一个自动变量,但让它遵循另一种分配方案(如 Method 2 Line 1)?

我很欣赏这可能涉及与编译器相关的讨论,但我没有为此添加标签

【问题讨论】:

  • 请不要误会,但我当然希望这是不可能的。如果它看起来不像一个指针,它的行为就不应该像一个指针。当然,在 C++ 中,事情并不总是那么明确,呵呵。
  • 我想这首先取决于您使用的操作系统。我想您可以摆弄链接器以重新排列内存布局。但我还不确定……
  • 你真的不应该把Matrix44作为参数;这个很贵。将这些参数声明为const Matrix44&。这可能会降低您首先在堆上分配矩阵的愿望吗?
  • 您可以使用对对象的引用:Matrix44 &mmat = *myMalloc(...);
  • @bash.d,您如何使用链接器重新安排内存布局?栈帧、栈等都内置在编译器中。当您执行 Matrix44 a; 时,编译器会在堆栈上为 a 保留空间。所有这些都是在链接之前完成的。就像 OP 一样,我很好奇这是否有技巧。标准当然没有定义堆栈...

标签: c++ c memory-management stack local-variables


【解决方案1】:

这是不可能的,自动变量是基于堆栈的。但是你可以在构造函数中做任何你想做的事情。因此,您的 Matrix44 将只是一个薄包装器,例如 Matrix44Impl 它将指向您的“自定义”内存。

【讨论】:

  • 实际上它们被分配在自动存储中,可以是任何东西,但是是的,大多数时候都是堆栈。
  • @sharptooth,我很好奇大部分时间来自哪里,因为这意味着在某些情况下不使用堆栈。你知道不使用堆栈来实现这一点的编译器吗?
  • @thang 这取决于您对“堆栈”的定义。 C++标准或多或少要求自动变量分配在A栈上,但并不是所有硬件都有硬件栈,很多人混淆了两者。
  • @JamesKanze,我提出的具体问题是你知道不使用堆栈来实现这个的编译器吗?this的意思自动变量。在标准中哪里需要在堆栈上分配自动变量?但是现在你买了它,哪个硬件没有硬件堆栈?现在有三个问题。 1. 哪个编译器不使用栈来实现自动存储? 2. 哪种机器架构根本没有硬件堆栈? 3. 标准中哪里要求自动变量分配到栈上?
  • 顺便说一句,不要试图争论。我真的很想知道。
【解决方案2】:

嗯,它不是 100% 完全符合您的要求,但是如果我理解正确的话,使用参考将 看起来像您想要的,并且行为或多或少与您想要的没有区别:

Matrix44& mmat = *new Matrix44(...);   // or *myMalloc() or whatever

mmat.Rotate(45.0);
bool res = matrixIsIdentity(mat);
...
delete &mmat; // or myFree(&mmat) or something similar

注意new 上的取消引用和delete 上的地址运算符,这无疑有点奇怪,但我不明白为什么它会在语法/语义上出错。编译器也接受它就好了,它“工作”。

不过,我强烈建议不要这样做。即使它“工作”得非常好,它也是误导性的。代码应该看起来像它正在做的那样,它应该做它看起来的样子。这段代码没有。

看起来像它存在于堆栈中的东西不应该被要求(或者,甚至可能!)交给delete,并且可以说,做一些奇怪的事情的代码并不真正“工作”,即使它“工作正常”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 2015-05-25
    • 2022-12-18
    • 2021-09-07
    • 1970-01-01
    • 2021-03-16
    相关资源
    最近更新 更多