多维数组作为具有显式大小的 VLA 函数参数

问题描述

背景

我正在编写计算流体动力学代码,我在其中处理向量和矩阵。因此,我想每隔一段时间将它们传递给函数

在整个代码中,向量和矩阵的内存分配如下

double* vec = calloc(n,sizeof(double));
double* mat = calloc(n * m,sizeof(double));

意思是我想访问这样的矩阵 mat[i * m + j]

为了“自动记录”函数,我想将这些数组的大小包含在函数原型中。对于矢量,这完美无缺,看起来像这样

// vecmat.h

void vec_print(size_t n,double const vec[restrict n]);

// vecmat.c

void vec_print(size_t n,double const vec[restrict n])
{
    for (size_t i = 0; i < n; ++i) {
        printf(DBL_FMT,vec[i]);
    }
    putchar('\n');
}

问题

为了保持一致,我想对矩阵做同样的事情,所以我这样做了

// vecmat.h

void mat_print(size_t n,size_t m,double const mat[restrict n * m]);

// vecmat.c

void mat_print(size_t n,double const mat[restrict n * m])
{
    for (size_t i = 0; i < n; ++i) {
        for (size_t j = 0; j < m; ++j) {
            printf(DBL_FMT,mat[i * m + j]);
        }
        putchar('\n');
    }
    putchar('\n');
}

问题来了。编译时,我收到以下警告

src/vecmat.c:21:49: warning: argument 3 of type ‘const double[restrict  n * m]’ declared with mismatched bound ‘n * m’ [-Wvla-parameter]
   21 | void mat_print(size_t n,double const mat[restrict n * m])
      |                                    ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
In file included from src/vecmat.c:1:
src/vecmat.h:16:49: note: prevIoUsly declared as ‘const double[restrict  n * m]’ with bound ‘n * m’
   16 | void mat_print(size_t n,double const mat[restrict n * m]);
      |                                    ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~

代码编译得很好,也产生了预期的输出,但我想去掉警告信息。 我知道 C 不使用提供的数组维度 n * m,而是地将参数转换为 double* restrict mat。这个问题似乎与我使用乘法和 gcc 以某种方式认为数组边界不一致的事实有关。

问题

我能否以某种方式修改我的语法以避免此编译器警告,或者我可以以某种方式完全禁用 gcc 中的此警告? (gcc 没有标志 -Wno-vla-parameter

EDIT -Wno-vla-parameter 确实存在并删除了警告

解决方

应按如下方式分配矩阵:

double (*mat)[m] = calloc(n * sizeof(*mat));

其中包含矩阵的函数调用应更改如下:

void mat_print(size_t n,double const mat[restrict n][m]);

这使得以更简单的形式 mat[i][j] 访问矩阵元素成为可能。

不幸的是 gcc 仍然抱怨,因为该函数使用了 const。 (https://godbolt.org/z/6xh5Exsff) 如果这也有一个巧妙的修复,我的初始和所有后续问题都将得到解决:D

其他资源:

附加信息

  • gcc 版本 11.1.0
  • -std=c99

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)