符号(float *)X
是一个演员表。如果矩阵乘法函数在使用之前被声明(或定义),则强制转换是必要的,因为传递给函数的类型不是float *
函数所期望的,而是float (*)[2]
(指向数组的指针)。强制转换告诉编译器“我们对这个 C 的了解比你多”,尽管这是一个非常值得商榷的命题。
这是问题中代码的轻微修改版本:
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[1][N];
void matrix_multiply(float *input_matrix1, float *input_matrix2, int m, int p, int n, float *output_matrix);
int main(void)
{
matrix_multiply( m1, m2, N, N, 1, result);
matrix_multiply(&m1[0][0], &m2[0][0], N, N, 1, &result[0][0]);
matrix_multiply((float*) m1, (float*) m2, N, N, 1, (float*) result);
}
void matrix_multiply(float *input_matrix1, float *input_matrix2, int m, int p, int n, float *output_matrix)
{
// Matrix Multiplication Routine
// input_matrix1 = input matrix (m x p)
// input_matrix2 = input matrix (p x n)
// m = number of rows in input_matrix1
// p = number of columns in input_matrix1 and the number of rows in input_matrix2
// n = number of columns in input_matrix2
// output_matrix = output matrix = input_matrix1*input_matrix2 (m x n)
//.....Code that does matrix multiplication
}
在 Mac OS X 10.8.4 上使用 GCC 4.7.1 编译时,输出为:
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -c matmul89.c
matmul89.c: In function ‘main’:
matmul89.c:10:5: warning: passing argument 1 of ‘matrix_multiply’ from incompatible pointer type [enabled by default]
matmul89.c:6:6: note: expected ‘float *’ but argument is of type ‘float (*)[2]’
matmul89.c:10:5: warning: passing argument 2 of ‘matrix_multiply’ from incompatible pointer type [enabled by default]
matmul89.c:6:6: note: expected ‘float *’ but argument is of type ‘float (*)[1]’
matmul89.c:10:5: warning: passing argument 6 of ‘matrix_multiply’ from incompatible pointer type [enabled by default]
matmul89.c:6:6: note: expected ‘float *’ but argument is of type ‘float (*)[2]’
matmul89.c: In function ‘matrix_multiply’:
matmul89.c:17:29: warning: unused parameter ‘input_matrix1’ [-Wunused-parameter]
matmul89.c:17:51: warning: unused parameter ‘input_matrix2’ [-Wunused-parameter]
matmul89.c:17:70: warning: unused parameter ‘m’ [-Wunused-parameter]
matmul89.c:17:77: warning: unused parameter ‘p’ [-Wunused-parameter]
matmul89.c:17:84: warning: unused parameter ‘n’ [-Wunused-parameter]
matmul89.c:17:94: warning: unused parameter ‘output_matrix’ [-Wunused-parameter]
$
未使用的参数警告是合理的;该函数仍然是一个没有代码的虚拟函数。matrix_multiply()
第 10 行是没有强制转换的调用。如您所见,GCC 诊断出矩阵参数的类型不是float *
指针数组而是指针数组。第二个调用是我编写它的方式,避免了任何强制转换。第三个调用使编译器接受带有强制转换的代码,它实际上可以正常工作,但实际上没有必要进行这种调整。
工作 C99 代码
如果你有 C99 可用,你可以利用 VLA(可变长度数组)来整齐地编写代码:
#include <stdio.h>
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[1][N];
void matrix_multiply(int m, int p, int n, float matrix1[m][p], float matrix2[p][n], float output[m][n]);
void matrix_print(const char *tag, int m, int n, float matrix[m][n]);
int main(void)
{
matrix_multiply(N, N, 1, m1, m2, result);
matrix_print("m1", N, N, m1);
matrix_print("m2", N, 1, m2);
matrix_print("m3", 1, N, result);
}
void matrix_multiply(int m, int p, int n, float matrix1[m][p], float matrix2[p][n], float output[m][n])
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
output[i][j] = 0.0;
for (int i = 0; i < m; i++)
for (int j = 0; j < p; j++)
for (int k = 0; k < n; k++)
output[i][k] += matrix1[i][j] * matrix2[j][k];
}
void matrix_print(const char *tag, int m, int n, float matrix[m][n])
{
printf("%s (%d x %d):\n", tag, m, n);
for (int i = 0; i < m; i++)
{
char *pad = "[";
for (int j = 0; j < n; j++)
{
printf("%s%6.3f", pad, matrix[i][j]);
pad = ", ";
}
printf("%s", " ]\n");
}
}
这会在没有警告的情况下编译并产生看似合理的输出:
m1 (2 x 2):
[ 1.000, -0.020 ]
[ 0.000, 1.000 ]
m2 (2 x 1):
[ 1.500 ]
[ 1.500 ]
m3 (1 x 2):
[ 1.470, 1.500 ]
编写代码来模拟使用 C89 的地址算术是很繁琐的——远非不可能,但很繁琐。
工作 C89 代码
#include <stdio.h>
#define N 2
static float m1[N][N] = {{1.0, -0.02}, {0.0, 1.0}};
static float m2[N][1] = {{1.5f}, {1.5f}};
static float result[1][N];
void matrix_multiply(float *matrix1, float *matrix2, int m, int p, int n, float *output);
void matrix_print(const char *tag, int m, int n, float *matrix);
int main(void)
{
matrix_multiply(&m1[0][0], &m2[0][0], N, N, 1, &result[0][0]);
matrix_print("m1", N, N, &m1[0][0]);
matrix_print("m2", N, 1, &m2[0][0]);
matrix_print("m3", 1, N, &result[0][0]);
return 0;
}
/*
** Matrix Multiplication Routine
** matrix1 = input matrix (m x p)
** matrix2 = input matrix (p x n)
** m = number of rows in matrix1
** p = number of columns in matrix1 and number of rows in matrix2
** n = number of columns in matrix2
** output = output matrix = matrix1 * matrix2 (m x n)
*/
void matrix_multiply(float *matrix1, float *matrix2, int m, int p, int n, float *output)
{
int i, j, k;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
output[i*n+j] = 0.0;
for (i = 0; i < m; i++)
for (j = 0; j < p; j++)
for (k = 0; k < n; k++)
output[i*n+k] += matrix1[i*p+j] * matrix2[j*n+k];
}
void matrix_print(const char *tag, int m, int n, float *matrix)
{
int i, j;
printf("%s (%d x %d):\n", tag, m, n);
for (i = 0; i < m; i++)
{
char *pad = "[";
for (j = 0; j < n; j++)
{
printf("%s%6.3f", pad, matrix[i*n+j]);
pad = ", ";
}
printf("%s", " ]\n");
}
}
C89 和 C99 代码的输出是相同的。