【问题标题】:Rewriting multi-dimensional VLAs in C89在 C89 中重写多维 VLA
【发布时间】:2016-01-17 21:49:00
【问题描述】:

我正在为一个开源项目重写一堆 C99 VLA,以便在 Visual Studio 中获得支持。所以我有很多类似

的陈述
void somefunc(double var[r]){...}

我重写了

void somefunc(double *var) {
     var = malloc(sizeof(double) * r);
     ...
     free(var);
}

我认为这是正确的方法。
问题是我开始看到一些更复杂的 VLA 声明,这让我很困惑。例如:

double *(*var)[length1][length2][length3] = malloc(sizeof(double *[length4][length1][length2][length3]));

所以对我来说,这基本上看起来像一个 5 维数组。 这在 C89 中显然是非法的,因为在 sizeof() 函数中使用了变量。

我对如何重写的猜测是:

double *****var = malloc(sizeof(double ****) * length1);
      for(int i = 0; i<length1; i++) {
            var[i] = malloc(sizeof(double ***) * length2);
            for(int j = 0; j<length2; j++) {
                 var[i][j] = malloc(sizeof(double **) * length3);
                      for(int k = 0; k<length3; k++) {
                           var[i][j][k] = malloc(sizeof(double *) * length4);
                      } 
            }
      }

虽然很乱,但这是我对如何重写上述语句的最佳猜测。这在技术上是否正确,是否有更好的方法可以解决这个问题?

【问题讨论】:

  • 如果你有这个double *(*var)[length1][length2][length3] = malloc(sizeof(double *[length4][length1][length2][length3]));,你应该从头重写所有程序。
  • 我建议你找到最初的开发者并拍摄他们,除非这是他们的玩笑。至于声明,这实际上是一个指向double 指针的三维数组的指针。
  • 在 C89 中无法从字面上重新编码多维可变大小数组。您可以像@szczurcio 所做的那样使用指针数组“伪造”多维数组。但这对指针空间和潜在的缓存负载有开销。更忠实的转录是定义函数和/或宏,以在一维数组中进行索引运算并重新编码所有数组访问。也就是说,对于 MxNxP 数组 A,您将访问元素 A[i][j][k] 作为 A1d[(i * N + j) * P + k]。当然A1d 分配有M*N*P 元素。这就是为什么 vla 被添加到语言中的原因!
  • 您对第一个示例(使用double var[r])的转换几乎肯定是错误的。
  • 为 VS 编写一个插件以使用适当的 C 编译器而不是像 clanggcc 的 MinGW 版本,这被认为可能更容易和更有效率 ...

标签: c pointers malloc c99 c89


【解决方案1】:

这是我的尝试:

double***** var = malloc(sizeof *var * length4);

for (int i = 0; i < length4; ++i)
{
    var[i] = malloc(sizeof *var[i] * length1);

    for (int j = 0; j < length1; ++j)
    {
        var[i][j] = malloc(sizeof *var[i][j] * length2);

        for (int k = 0; k < length2; ++k)
        {
            var[i][j][k] = malloc(sizeof *var[i][j][k] * length3);

            for (int l = 0; l < length3; ++l)
            {
                var[i][j][k][l] = NULL;     
                // var[i][j][k][l] is a double* - you can allocate some room for a double here, or assign the address of an existing variable
            }
        }
    }
}

与您的类似,但请注意我在第一个 malloc 中如何使用 length4。如果您查看您的原始声明,var 是一个 指针,指向 double* 的三维数组。正如我们可以从右侧的malloc 调用中推断出的,为length4 这样的数组分配了内存,因此您可以将var 视为length4 的数组double* 的三维数组。

我仍然坚持认为,任何将此类内容放入生产代码中的人都应该当场处决(好吧,作为维护者,你可以原谅)。

IIRC 在 fors 中声明变量不是有效的 C89,但您可以将这些变量移到范围的顶部。

请注意,正如@immibis 在 cmets 中指出的那样,您的第一次转换很可能是一个错误; double *var 是函数的一个参数,这意味着它是按值传递的,所以你在函数内部对它所做的任何更改在外部都不可见,最重要的是,你 malloc 一些内存,用它做一些事情,然后free 它。即使您正在修改传递的指针 - 这将要求参数类型为 double** - 仍然不需要传递变量,因此您可以在本地独占使用它。您很可能想要malloc 函数外部的内存并向它传递一个有效的指针(希望是大小)。

【讨论】:

  • sizeof *varsizeof(double ****) 之间有区别还是只是偏好问题?感谢您的帮助。
  • @EthanPavolik 不,是一样的,这完全取决于你(括号相同,sizeof(*var) 也是有效的`)。
猜你喜欢
  • 2015-08-17
  • 2016-04-06
  • 1970-01-01
  • 1970-01-01
  • 2022-12-18
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多