gpt4 book ai didi

c - VLA 作为函数参数的语法

转载 作者:太空宇宙 更新时间:2023-11-04 01:02:48 28 4
gpt4 key购买 nike

我写了最简单的矩阵乘法代码来完成我对 C99 VLA 的理解。让我有点困惑的是,当我在函数定义的参数列表中声明一个指向 VLA 的指针时。

例如,在 fill_matrix_randomly 中,声明为 double (*m)[n_cols] 的参数 m 可以正常编译。 double (*m)[*] 是一个编译错误,因为[*] 只能出现在声明中。 double (*m)[] 也是一个错误,因为我无法访问不完整类型的数组。到现在为止没有什么奇怪的,但是。 double (*m)[n_rows] 编译正常甚至运行正常? double (*m)[1]double (*m)[2] 也可以,我在这里真的很困惑。帮助我减少困惑。

#include <stdio.h>
#include <stdlib.h>

static void fill_matrix_randomly(int, int, double (*)[*]);
static void print_matrix(int, int, double (*)[*]);
static void multiply_matrices(int, int, int, double (*restrict)[*],
double (*restrict)[*], double (*restrict)[*]);

int main(void) {
const int a = 1, b = 3, c = 5;
double m[a][c], m2[a][b], m3[b][c];
fill_matrix_randomly(a, b, m2);
fill_matrix_randomly(b, c, m3);
multiply_matrices(a, b, c, m, m2, m3);
print_matrix(a, b, m2);
print_matrix(b, c, m3);
print_matrix(a, c, m);
}

static void fill_matrix_randomly
(int n_rows, int n_cols, double (*m)[n_cols]) {
for (int i = 0; i < n_rows; ++i) {
for (int j = 0; j < n_cols; ++j) {
m[i][j] = (double)rand() / RAND_MAX + 1;
}
}
}

static void print_matrix(int n_rows, int n_cols, double (*m)[n_cols]) {
for (int i = 0; i < n_rows; ++i) {
printf("[ ");
for (int j = 0; j < n_cols; ++j) {
printf("%.3f", m[i][j]);
if (j != n_cols - 1) {
printf(", ");
} else {
printf(" ]\n");
}
}
}
putchar('\n');
}

static void multiply_matrices
(int n, int m, int p, double (*restrict r)[p],
double (*restrict a)[m], double (*restrict b)[p]) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < p; ++j) {
double sum = 0;
for (int k = 0; k < m; ++k) {
sum += a[i][k] * b[k][j];
}
r[i][j] = sum;
}
}
}

最佳答案

double (*m)[n_rows] compiles fine and even runs fine

如果您声明函数参数类型为double (*)[n_rows],但传递的参数类型为double (*)[n_columns],并且n_rows 不同于n_columns,则行为未定义。

这同样适用于 double (*m)[1]double (*m)[2] 变体。

参数传递要求参数类型与参数类型兼容。在指向数组的指针的情况下,指针必须指向兼容的数组类型。在您的情况下,以下情况适用

6.7.5.2 Array declarators

6 For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.

显然,没有人可以合理地期望在编译时捕获此类违规行为,因为编译器通常无法在编译时预测和执行运行时关系(VLA 大小)。

在提交此违规行为(这本身足以触发 UB)后,您可以通过对 fill_matrix_randomly 中的数组执行越界访问来继续提交另一个违规行为。

至于运行它...我不清楚您认为带有 double (*m)[n_rows] 的代码“运行良好”的想法。一个快速的实验表明,如果你幸运的话,像那样对编译器说谎会导致数组填充不正确

http://coliru.stacked-crooked.com/a/6032864f2baa2eae

如果你不那么幸运,或者崩溃

http://coliru.stacked-crooked.com/a/7ba1002e3150bd1c

关于c - VLA 作为函数参数的语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31932730/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com