You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在if语句内分配不同类型数组的C语言最佳实践

C语言中按条件分配不同类型数组的最佳实践

背景与问题

最近对CUDA产生了兴趣,感觉C程序转CUDA比Fortran更自然(除核心问题外,这个观点是否属实?),学习C时发现if语句的作用域规则和Fortran差异很大。

比如下面的Fortran代码可以正常运行并输出预期结果:

program test
real(kind=selected_real_kind(15)),  allocatable :: arr_double(:)
integer                          ,  allocatable :: arr_int(:)
logical                                         :: flag_int, flag_double

flag_int    = .false.
flag_double = .true.

if (flag_int) then
  allocate(arr_int(10))
  arr_int = 1
  print *, arr_int
else if (flag_double) then
  allocate(arr_double(10))
  arr_double = 1.
  print *, arr_double
end if

if (flag_int) then
  deallocate(arr_int)
else if (flag_double) then
  deallocate(arr_double)
end if

end program

输出结果:

1.00000000000000        1.00000000000000        1.00000000000000 
  1.00000000000000        1.00000000000000        1.00000000000000 
  1.00000000000000        1.00000000000000        1.00000000000000 
  1.00000000000000     

但对应的C代码(icc编译)会直接报错:

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

int main() {
  size_t dim1;
  bool   flag_int, flag_double;

  flag_int    = false;
  flag_double = true;

  if (flag_int) {
    int (*arr1d) = calloc(dim1, sizeof(*arr1d));
  }else if(flag_double) {
    double (*arr1d) = calloc(dim1, sizeof(*arr1d));
  }

  free(arr1d);

}

编译失败的原因是C语言中if语句块内声明的变量仅具有局部作用域,无法在块外访问。那么如果要根据if条件分配不同类型(int或double)的数组,C语言的最佳实践是什么?

注:该问题仅为学习C时的练习,不会用于实际工作。

关于C转CUDA更自然的补充

这个观点确实有合理性:CUDA本身是基于C/C的扩展,语法和C高度兼容,指针操作、线程索引计算等CUDA核心操作和C的编程习惯契合度很高;而Fortran转CUDA需要适配Fortran的数组模型和CUDA的C风格接口,虽然有CUDA Fortran支持,但生态和资料量远不如C/C版本的CUDA,从学习和上手角度来看,C转CUDA确实更顺畅。

解决方案

方法1:使用void指针+类型标记

利用C中void*可以指向任意类型的特性,用通用指针存储数组地址,同时用一个标记变量记录数组类型,后续操作时通过类型转换访问对应数据。

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

int main() {
    size_t dim1 = 10; // 必须先初始化,避免未定义行为
    bool flag_int = false;
    bool flag_double = true;

    void* arr1d = NULL;
    enum { TYPE_INT, TYPE_DOUBLE } arr_type;

    if (flag_int) {
        arr1d = calloc(dim1, sizeof(int));
        arr_type = TYPE_INT;
        // 赋值并打印
        int* int_arr = (int*)arr1d;
        for (size_t i = 0; i < dim1; i++) {
            int_arr[i] = 1;
        }
        for (size_t i = 0; i < dim1; i++) {
            printf("%d ", int_arr[i]);
        }
        printf("\n");
    } else if (flag_double) {
        arr1d = calloc(dim1, sizeof(double));
        arr_type = TYPE_DOUBLE;
        // 赋值并打印
        double* double_arr = (double*)arr1d;
        for (size_t i = 0; i < dim1; i++) {
            double_arr[i] = 1.0;
        }
        for (size_t i = 0; i < dim1; i++) {
            printf("%.15lf ", double_arr[i]);
        }
        printf("\n");
    }

    // 释放内存,free不关心指针类型
    if (arr1d != NULL) {
        free(arr1d);
    }

    return 0;
}

方法2:提前声明所有可能的指针

和你提供的Fortran代码逻辑最接近,提前声明不同类型的指针,在对应分支中分配内存,释放时根据相同条件判断要释放的指针。

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

int main() {
    size_t dim1 = 10;
    bool flag_int = false;
    bool flag_double = true;

    int* arr_int = NULL;
    double* arr_double = NULL;

    if (flag_int) {
        arr_int = calloc(dim1, sizeof(int));
        for (size_t i = 0; i < dim1; i++) {
            arr_int[i] = 1;
        }
        for (size_t i = 0; i < dim1; i++) {
            printf("%d ", arr_int[i]);
        }
        printf("\n");
    } else if (flag_double) {
        arr_double = calloc(dim1, sizeof(double));
        for (size_t i = 0; i < dim1; i++) {
            arr_double[i] = 1.0;
        }
        for (size_t i = 0; i < dim1; i++) {
            printf("%.15lf ", arr_double[i]);
        }
        printf("\n");
    }

    // 根据条件释放对应指针
    if (flag_int) {
        free(arr_int);
    } else if (flag_double) {
        free(arr_double);
    }

    return 0;
}

额外注意事项

  • 原C代码中的dim1未初始化,会导致calloc的大小不确定,属于未定义行为,实际编写时必须先给变量赋值。
  • C的块级作用域是语言核心特性:变量在{}内声明时,仅能在该块及嵌套块中访问,这和Fortran的作用域规则完全不同(Fortran中程序单元内声明的变量,整个单元都可访问)。

内容的提问来源于stack exchange,提问作者Sangjun Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:16:08