C语言用联合体实现伪多态:矩阵块指针赋值问题求解
在C语言中用联合体实现矩阵块伪多态的问题与解决
问题背景
我想在C语言中用联合体实现伪多态,定义了如下矩阵块数据结构:
// Matrix block typedef struct { union { int i; double d; } *a; // 指向矩阵块第一个元素的指针 int k; // 块索引 int p; // 块的行数 int q; // 块的列数 int m; // 矩阵总行数 int n; // 矩阵总列数 int r; // 块所属的MPI进程编号 } mtrx_blk;
目标是通过联合体指针a适配double和int类型的矩阵,用同一个mtrx_blk结构体处理不同类型的矩阵块。尝试为double类型矩阵A创建块时,使用了如下代码:
// 遍历每个块 for (int k = 0; k < NBLK; k++) { blk[k] = (mtrx_blk) { .a = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; }
出现类型不兼容的编译错误:
gcc -std=c11 -pedantic-errors struct-union.c -o struct-union struct-union.c: In function 'main': struct-union.c:52:36: error: initialization of 'union <anonymous> *' from incompatible pointer type 'double *' [-Wincompatible-pointer-types] 52 | blk[k] = (mtrx_blk) { .a = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; | ^ struct-union.c:52:36: note: (near initialization for '(anonymous).a')
改用.a.d = &A[k*P*Q]的写法后,编译仍失败:
gcc -std=c11 -pedantic-errors struct-union.c -o struct-union struct-union.c: In function 'main': struct-union.c:52:31: error: field name not in record or union initializer 52 | blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; | ^ struct-union.c:52:31: note: (near initialization for '(anonymous)') struct-union.c:52:38: error: initialization of 'union <anonymous> *' from incompatible pointer type 'double *' [-Wincompatible-pointer-types] 52 | blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; | ^ struct-union.c:52:38: note: (near initialization for '(anonymous).a')
提出两个问题:
- 正确的赋值方式是什么?
- 我的逻辑是否正确,能否用类似
.a.i = &B[k*P*Q]的语法处理int类型矩阵B?
完整源码如下:
#include <stdlib.h> // Matrix block typedef struct { union { int i; double d; } *a; // pointer to first element in matrix block int k; // block index int p; // no. of block rows int q; // no. of block columns int m; // no. of matrix rows int n; // no. of matrix columns int r; // MPI rank of block owner } mtrx_blk; int main(int argc, char *argv[]) { // no. of matrix rows int const M = 10; // no. of matrix columns int const N = 10; // no. of blocks int const NBLK = 2; // no. of block rows int const P = M/NBLK; // no. of block columns int const Q = N; // allocate memory for matrix double *A = (double*) malloc(M*N*sizeof(double)); // allocate array of blocks mtrx_blk *blk = (mtrx_blk*) malloc(NBLK*sizeof(mtrx_blk)); // for each block for (int k = 0; k < NBLK; k++) { blk[k] = (mtrx_blk) { .a.d = &A[k*P*Q], .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; } // free memory of array of blocks free(blk); // free memory of matrix free(A); return 0; }
问题解答
1. 正确的赋值方式
你当前的结构体定义存在逻辑错误:a是指向单个匿名联合体的指针,但你实际需要的是指向int或double类型数组的指针。正确的做法是将联合体定义为包含指针类型的成员,而非让a指向联合体:
修改后的结构体定义:
typedef struct { union { int *i; // 指向int类型矩阵块的指针 double *d; // 指向double类型矩阵块的指针 } a; // 联合体成员,而非联合体指针 int k; int p; int q; int m; int n; int r; } mtrx_blk;
此时给double类型矩阵块赋值的代码可以写成:
for (int k = 0; k < NBLK; k++) { blk[k] = (mtrx_blk) { .a.d = A + k*P*Q, // 等价于&(A[k*P*Q]),写法更简洁 .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; }
这样就能通过.a.d直接关联到double数组的起始地址,编译不会报错。
2. 逻辑修正与int矩阵的处理
你原本的逻辑方向是对的,但结构体定义错误导致无法实现。修正结构体后,完全可以用类似的语法处理int类型矩阵B:
假设已分配int类型矩阵int *B = malloc(M*N*sizeof(int));,赋值代码如下:
for (int k = 0; k < NBLK; k++) { blk[k] = (mtrx_blk) { .a.i = B + k*P*Q, .k = k, .p = P, .q = Q, .m = M, .n = N, .r = k }; }
需要注意的是,使用时需要明确当前块的类型(比如可以在结构体中新增一个枚举字段标记类型:enum { TYPE_INT, TYPE_DOUBLE } type;),避免访问错误的联合体成员导致未定义行为。
内容的提问来源于stack exchange,提问作者mabalenk
相关产品推荐
相关产品推荐

