【问题标题】:Passing parameters to a function to efficiently create array allocated on the stack将参数传递给函数以有效地创建分配在堆栈上的数组
【发布时间】:2017-07-22 08:44:09
【问题描述】:

我有一个需要外部参数的函数,然后创建在该函数内部大量使用的变量。例如。代码可能如下所示:

void abc(const int dim);

void abc(const int dim) {
    double arr[dim] = { 0.0 };
    for (int i = 0; i != dim; ++i)
        arr[i] = i;
    // heavy usage of the arr
}

int main() {
    const int par = 5;
    abc(par);
    return 0;
}

但是我得到一个编译器错误,因为堆栈上的分配需要编译时常量。当我尝试使用 _malloca 在堆栈上手动分配时,代码的时间性能变差了(与我在 abc() 函数中声明常量 par 的情况相比)。而且我不希望数组 arr 在堆上,因为它应该只包含少量的值,并且它会在函数内部经常使用。有没有办法在保持将数组的大小参数传递给函数的可能性的同时结合效率?

编辑:我正在使用 MSVC 编译器,但收到错误 C2131:表达式在 VC 2017 中未计算为常量。

【问题讨论】:

  • C99居然支持变长数组,这是哪个编译器?
  • 您需要将其标记为constexpr 或使用模板参数。
  • 请准确选择一种编程语言。
  • 在这个函数的运行之间大小会改变吗?您是否考虑过将其设为函数中的静态变量,或者将其分配到外部并将其传递给您的函数?
  • 你得到了一个错误 - 该错误的内容与问题有些相关...... 逐字内容

标签: c arrays performance


【解决方案1】:

如果您使用的是现代 C 编译器,它实现了整个 C99 或具有可变长度数组扩展的 C11,只需稍作修改即可:

void abc(const int dim);

void abc(const int dim) {
    double arr[dim];
    for (int i = 0; i != dim; ++i)
        arr[i] = i;
    // heavy usage of the arr
}

int main(void) {
    const int par = 5;
    abc(par);
    return 0;
}

double arr[dim] 可以工作 - 它没有编译时常量大小,但在运行时知道它的大小就足够了。但是,这样的VLA无法初始化。

不幸的是,MSVC 不是现代 C 编译器/在 MS,他们不想自己实现 VLA - 我什至怀疑他们是 VLA 被设为可选的重要原因C11,因此您需要在main 中定义数组,然后将指向它的指针传递给函数abc;或者如果大小是全局常量,则使用实际的编译时常量,即 #define

但是,您没有显示您遇到性能问题的实际代码。如果编译器知道迭代次数,它很可能会产生优化的输出 - 如果这是真的,那么“全局定义的大小”可能是获得出色性能的唯一方法。

【讨论】:

    【解决方案2】:

    很遗憾,Microsoft 编译器不支持可变长度数组。

    如果数组不是太大,您可以按所需的最大可能大小进行分配,并将指向该堆栈数组的指针和一个维度传递给函数。这种方法可以帮助限制分配的数量。

    另一种选择是实现一个简单的堆分配全局池,供这种类型的函数使用。池将在堆上分配一个大的连续块,然后您可以获得指向池中预留的指针。这种方法的好处是您不必担心堆栈上的过度分配会导致分段错误(可变长度数组可能会发生这种情况)。

    【讨论】:

      猜你喜欢
      • 2013-04-14
      • 2021-12-30
      • 1970-01-01
      • 2017-04-21
      • 1970-01-01
      • 2014-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多