行为
支持 #466
打开fortran 多维数组与 c++ 的区别
状态:
新建
优先级:
普通
指派给:
-
开始日期:
2026-01-15
计划完成日期:
% 完成:
0%
预期时间:
#2:
描述
从 C++ 背景来看,Fortran 多维数组有几个关键区别需要特别注意,尤其是内存布局的差异会直接影响代码逻辑和性能。
1. 内存布局:列主序 vs 行主序
这是最本质的区别:
-
C++:行主序(Row-major)
int arr[3][4]; // 内存中:arr[0][0], arr[0][1], ..., arr[0][3], arr[1][0], ... // 遍历性能:for(i) for(j) 访问 arr[i][j] 是连续的 -
Fortran:列主序(Column-major)
integer :: arr(3,4) ! 内存中:arr(1,1), arr(2,1), arr(3,1), arr(1,2), ... ! 遍历性能:do j = 1,4; do i = 1,3; 访问 arr(i,j) 是连续的
影响:嵌套循环顺序需要反转,否则性能会大幅下降。
2. 下标起始:默认 1-based
integer :: a(10) ! 索引 1..10
integer :: b(0:9) ! 可以显式指定 0..9
integer :: c(-5:5) ! 甚至可以是负数范围
3. 数组声明语法
! Fortran(维度在后)
real :: matrix(10, 20) ! 10行20列
real, allocatable :: dyn(:,:) ! 可分配数组
! C++(维度在前)
double matrix[10][20];
std::vector<std::vector<double>> dyn;
4. 数组整体操作
Fortran 支持直接的数组运算,无需循环:
real :: a(100), b(100), c(100)
a = b + c ! 逐元素相加
a = sqrt(b) ! 逐元素开方
where (b > 0) a = log(b)
C++ 需要 std::transform 或手写循环。
5. 数组切片
! 提取子数组
real :: big(100, 100), small(10, 10)
small = big(1:10, 21:30) ! 直接切片复制
6. 函数传参:形状信息可保留
subroutine process(arr)
real, intent(inout) :: arr(:,:) ! 假设形状,接收任意大小
! 可通过 size(arr,1) 获取各维度
end subroutine
! 调用
call process(my_array) ! 无需额外传递维度信息
C++ 中通常需要模板或额外参数传递维度。
7. 动态数组
real, allocatable :: arr(:,:)
allocate(arr(n, m))
...
deallocate(arr)
! 自动重新分配
arr = reshape(source_array, [new_n, new_m])
总结对比表¶
| 特性 | Fortran | C++ |
|---|---|---|
| 内存顺序 | 列主序 | 行主序 |
| 默认索引 | 1-based | 0-based |
| 数组运算 | 原生支持 | 需库/手动实现 |
| 切片 | 语法级支持 | 需指针/引用操作 |
| 传参 | 可保留形状信息 | 通常退化或需模板 |
| 性能敏感 | 按列遍历 | 按行遍历 |
建议:从 C++ 转向 Fortran 时,最需要注意的就是反转循环顺序以匹配列主序,否则缓存命中率会很差。
由 李立奎 更新于 3 天 之前
如果是 Fortran 77,限制会更多,对 C++ 程序员来说会更不友好:
1. 无动态数组
! F77:必须是固定大小或显式传参
subroutine process(arr, n, m)
integer n, m
real arr(n, m) ! 需要显式传递维度作为参数
end subroutine
! 无法像 F90+ 那样用 allocatable 或 assumed shape
2. 循环必须写全
do 10 j = 1, n
do 10 i = 1, m
arr(i, j) = ...
10 continue
! 无法像 F90+ 用 forall 或数组整体运算
3. 无数组语法糖
- 没有
arr = b + c这样的整体赋值 - 没有
arr(1:10)这样的切片语法 - 所有操作必须手写循环
4. 字符串是字符数组
character*80 str ! 固定长度,不像 C++ 的 std::string
5. 无接口检查
- 函数调用不检查数组边界和类型
- 容易传错维度导致内存越界
6. 列主序依然成立
虽然语法受限,但列主序规则不变,遍历顺序仍需注意:
! 正确(连续访问内存)
do j = 1, n
do i = 1, m
arr(i, j) = ...
总结:F77 的数组系统更像 C 的原始数组,没有现代 Fortran 的高级特性,但内存布局和性能考量点仍然相同。
行为