我设法将5000多个Fortran 77程序的行代码手动转换为C ++,但是转换没有按计划进行。因此,我尝试使用我的Fortran 77程序调试C ++程序。在fortran中,我开发了一个子例程,该例程接受一个数组,并将数组索引及其值打印到以逗号分隔的文件中。我正在尝试在C ++中做类似的事情。但会违反“ double temp1 [tempi]”声明。在对函数的所有调用中,数组的大小不必相同。因此,我无法将其编码为“ double temp1 [21]”,因为下一次是25。Fortran通过引用传递数组。你建议我做什么。
我设法实现了Fortran程序。这样做的目的是从c ++程序中获取变量内存转储,并使用vba比较Excel中的值,以查看哪个变化最大,然后从C ++程序中着眼于该变量,这是调试的起点。
c ++代码逻辑:
void singlearrayd(double temp1[tempi], int tempi, string str1){
for (int md_i = 1; md_i <= tempi; md_i++){
cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
}
}
int main(){
double askin[22];
double fm[26];
singlearrayd(askin,22,"askin");
singlearrayd(fm,26,"fm");
return 0;
}
Fortran 77代码逻辑:
PROGRAM PRINT_MEMORY
real*8 :: ASKIN(21)
real*8 :: FM(25)
CALL SINGLEARRAYD(ASKIN,21,"ASKIN")
CALL SINGLEARRAYD(FM,25,"FM")
END PRINT_MEMORY
SUBROUTINE SINGLEARRAYD(TEMP1,TEMPI,STR1)
IMPLICIT NONE
CHARACTER(LEN=*) :: STR1
INTEGER*4 MD_I,TEMPI
REAL*8, DIMENSION(1:TEMPI) :: TEMP1
DO MD_I = 1, TEMPI
WRITE(51,'(ES25.16E3,A1,A25,A1,I5,A1)') TEMP1(MD_I),',',STR1,'(',
1 MD_I,')'
ENDDO
ENDSUBROUTINE SINGLEARRAYD
答案 0 :(得分:4)
您的代码中存在多个问题。
在C ++中,本机数组(如askin
中的main()
)在传递给函数时会转换为指针。因此,无需在参数列表中的数组上声明维,但仍然需要传递第二个参数,因为您要指定大小。
这意味着C ++函数应具有以下形式
void singlearrayd(double temp1[], int tempi, std::string str1)
或(等效)
void singlearrayd(double *temp1, int tempi, std::string str1)
在上面请注意,我已将第三个参数的类型全名指定为std::string
。在很多情况下,最好避免使用using namespace std
。
第二个问题是您假设Fortran数组索引和C ++数组索引相同。实际上,Fortran数组索引是基于1的(默认情况下,数组的第一个元素的索引为1),而C ++数组索引是基于0的(数组的第一个元素的索引为零)。在C ++中使用Fortran数组索引会导致不确定的行为,因为它将访问有效范围之外的元素。
第三个(潜在)问题是您的函数定义了两个名为md_i
的变量(一个在函数中,一个在循环内)。最好避免这样做。
解决以上所有问题将使您的功能变为(完整)
void singlearrayd(double temp1[], int tempi, std::string str1)
{
for (int md_i = 0; md_i < tempi; ++md_i) // note the differences here carefully
{
cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
}
}
第四个问题是C ++中的main()
返回int
,而不是void
。
第五个问题是main()
在singlearrayd()
打印它们之前没有初始化数组。在Fortran中,函数本地的数组(通常)是零初始化的。在C ++中,默认情况下未对它们进行初始化,因此访问它们的值(例如打印它们)会产生不确定的行为。
int main()
{
double askin[21] = {0.0}; // initialise the first element. Other elements are initialised to zero
double fm[21] = {0.0};
singlearrayd(askin,21,"askin");
singlearrayd(fm,25,"fm");
}
这将使您的代码正常工作。但是实际上,有可能进行改进。第一个改进是使用标准容器而不是数组。标准容器知道它们的大小,因此可以简化您的功能。其次,通过引用传递非平凡的参数(例如容器或字符串)-如果对参数不做任何更改,最好使用const
引用。与Fortran不同,在Fortran中,函数参数通常通过引用按DEFAULT传递,因此有必要在C ++中有意地引入引用。
#include <vector>
void singlearrayd(const std::vector<double> &temp1, const std::string &str1)
{
for (std::size_t md_i = 0; md_i < temp1.size(); ++md_i)
{
cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
}
}
int main()
{
std::vector<double> askin(21); // askin has 21 elements, initialised to zero
std::vector<double> fm(21);
singlearrayd(askin, "askin");
singlearrayd(fm, "fm");
}
C ++容器还支持迭代器-与使用数组索引相比,迭代器在实践中更安全,而且通常效率更高。我将其作为练习来学习如何使用它们。
但是要注意的一个关键信息是:不要认为从Fortran到C ++的简单机械翻译就行。您已经证明了这种假设的陷阱。在尝试将太多代码从Fortran转换为C ++之前,请花一些时间学习C ++。这对于使C ++代码正确运行以及使其高效运行都是必需的。
答案 1 :(得分:2)
一个更现代的实现是
#include <string>
#include <array>
#include <iostream>
template <std::size_t size, class U>
void singlearrayd(const std::array<U, size>& temp1, const std::string& str1){
int i = 0;
for (const auto& x : temp1)
std::cout << x << "," << str1 << "(" << (i++) << ")";
}
int main(){
std::array<double, 21> askin;
std::array<double, 21> fm;
singlearrayd(askin, "askin");
singlearrayd(fm, "fm");
return 0;
}
请注意,在上面的代码中,两个数组askin
和fm
未初始化。大概在实际代码中,您将在调用singlarrayd
之前已经对其进行了初始化。
另外,请记住main
必须返回int
。
答案 2 :(得分:0)
感谢您的宝贵见解和评论。我认为最好的方法是使用
void singlearrayd(double *temp1, int tempi, std::string str1)
扩展了这个想法并使用Google进行了更多研究,我能够将这个想法扩展到处理2D和3D数组。
void doublearrayd(double *temp1, int tempi, int tempj, std::string str1){
for (int md_j = 1; md_j<tempj; md_j++){
for (int md_i = 1; md_i<tempi; md_i++){
std::cout << *(temp1 + md_i*tempj + md_j) << "," << str1 << "(" << md_i << ";" << md_j << ")" << std::endl;
}
}
}
void triplearrayd(double *temp1, int tempi, int tempj, int tempk, std::string str1){
for (int md_k = 1; md_k < tempk; md_k++){
for (int md_j = 1; md_j<tempj; md_j++){
for (int md_i = 1; md_i<tempi; md_i++){
std::cout << *(temp1 + md_i*tempj*tempk + md_j*tempk + md_k) << "," << str1 << "(" << md_i << ";" << md_j << ";" << md_k << ")" << std::endl;
}
}
}
}
https://en.wikipedia.org/wiki/Row-_and_column-major_order
How can I pass a dynamic multidimensional array to a function?