Leo*_*ino 11 c c++ unix icc visual-studio-2008
我已经阅读了几种结合C和C++代码的方法,但是,我仍然对如何处理我的情况感到困惑.这是我的问题:
我有一个比较大的量的C语言代码(包括各种.c和.h文件),其用于建模在有限和离散元件的固体.该代码具有相对简短的主函数,其中for循环中顺序调用各种其他函数(来自其他文件).在Unix(icc编译器)和Visual Studio中编译时,此代码工作正常.
我在C++中有其他代码可以解决分子动力学相互作用.此代码还包含各种文件,并在Unix(icpc编译器)和VS中运行良好.两者都是独立程序,具有自己的输入和输出文件集.
我需要做的是以我的C程序在其主循环中"调用"C++代码的方式运行这两个程序.一些信息需要在两个代码之间双向传递,这两个代码可以是数组(或指针)的形式.
最简单的方法是什么?
特别是,根据我读过的建议,我有多个问题:
extern "C" {}吗?extern "C"在我的C函数中使用吗?extern "C"在我的C++文件中使用?(标题?函数?所有这些?还是只需要从C程序调用的那些?)main功能.我可以简单地重命名我的C++ main函数吗?main函数从C 转换为C++吗?main在C++中重命名并由我的C代码"调用";第五,实现传输信息?)抱歉,长文和多个问题.我对C相对较新,甚至比C++更新,所以即使我对这些程序的词汇量有限.
谢谢您的帮助.任何提示将不胜感激.如果您需要其他信息,请告诉我们.
这是我的C代码的"主要"功能:
#include "Yproto.h"
void show_time_info(YDC ydc,CHR Ystage[3]);
main(argc, argv)
INT argc; char **argv;
{ CHR c1name[300]; /* name of the problem i.e. input file */
struct YD_struct yd; /* Y database */
YDC ydc=&(yd.ydc); /* Y control database */
YDE yde=&(yd.yde); /* Y element database */
YDI ydi=&(yd.ydi); /* Y interaction database */
YDN ydn=&(yd.ydn); /* Y node database */
YDB ydb=&(yd.ydb); /* Y borehole database */
YDS yds=&(yd.yds); /* Y source (inter. fluid) database */
YDO ydo=&(yd.ydo); /* Y output database */
YDPE ydpe=&(yd.ydpe); /* Y property database for elements */
YDPN ydpn=&(yd.ydpn); /* Y property database for nodes (BC) */
YDPJ ydpj=&(yd.ydpj); /* Y property database for joints */
YDPM ydpm=&(yd.ydpm); /* Y property database for meshing */
INT Tctrlc, itimes=0;
CHR *p=NULL;
/* get name of the problem */
if(argv[1]!=NULL)
{ CHRcpy(c1name,argv[1]);
}
else
{ CHRwcr(stdout);
CHRw(stdout," please define input file names: "); CHRwcr(stdout);
CHRw(stdout," >");
fgets(c1name,sizeof(c1name),stdin);
if((p=strrchr(c1name,'\n'))!=NULL) *p = '\0';
}
strcpy(ydc->cfiname, c1name); ydc->cfiname[255]='\0';
ydc->finp=FILENULL; ydc->fcheck=FILENULL;
/* Process while any input */
while(Yrd(c1name,&yd)>0)
{ itimes=itimes+1;
CHRw(stdout,"NEW INPUT: "); CHRw(stdout, c1name); CHRwcr(stdout);
if(Ycheck(&yd)<0) break; date_and_time(ydc->cruntime); timestamp();
CHRw(stdout, "Start calculating ...\n");
omp_set_num_threads(8);
for(ydc->ncstep=ydc->ncstep;ydc->ncstep<ydc->mcstep;ydc->ncstep++)
{ show_time_info(ydc,"Ymd"); /* show time information */
Ymd(ydc,yde,ydi,ydn,ydpe,ydpn,ydpm); /* mesh elements */
/********** HERE IS WHERE I WOULD LIKE TO CALL MY C++ PROGRAM ***************/
Yfd(ydc,yde,ydn,ydi,ydo,ydpe,ydpn,ydpj); /* nodal forces */
Ybor(ydc,yde,ydn,ydb,yds,ydpe,ydpj,ydpn); /* borholes, inter. fluid */
Ycd(ydc,yde,ydi,ydn,ydpe,ydpn); /* contact detection */
Yid(ydc,yde,ydi,ydn,ydo,ydpe,ydpn, ydpj,ydpm); /* interaction */
Yod(c1name,&yd); /* output results */
Ysd(ydc,yde,ydn,ydo,ydpe,ydpn ); /* solve equations */
Yfrd(ydc,yde,ydi,ydn,ydpe,ydpn,ydpj,ydpm); /* fracture */
ydc->dctime=ydc->dctime+ydc->dcstec; /* update time */
/* CTRL-C Interruption */
Tctrlc = enablc(ydc->dctime, ydc->ncstep, ydc->mcstep);
if(Tctrlc!=1) break;
}
}
/* Termination */
CHRw(stderr," ***** Y HAS ORDERLY FINISHED *****"); CHRwcr(stderr);
CHRw(stderr,"Press a key to continue"); CHRwcr(stderr);
getchar();
}
Run Code Online (Sandbox Code Playgroud)
回答后24小时更新
我按照提供的答案按照建议进行操作,我的问题的解决方案比原先想象的要简单得多(尽管在开始工作之前我确实需要探索几个选项).最好的部分是它适用于Unix和Visual Studio.以下是我采取的步骤摘要:
将我的主C文件转换为C++.为此,将包含main我的C代码函数的文件重命名为.cpp扩展名(从Yc更改为Y.cpp)并更改main函数的开头:
main(argc, argv)
INT argc; char **argv;
Run Code Online (Sandbox Code Playgroud)
至
int main(int argc,char **argv)
Run Code Online (Sandbox Code Playgroud)
为了使C++'友好'.(注意:我知道将文件重命名为.cpp并不重要,但我认为为了清晰起见,最好这样做).
用我的所有C头文件包装
#ifdef __cplusplus
extern "C" {
#endif
Run Code Online (Sandbox Code Playgroud)
在开始时,和
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
在末尾.
更改我的mainC++函数的名称和(暂时)不使用参数.我把它命名了int Ynano().
创建一个名为Y_NANO.h的新头文件(Y_NANO.cpp是包含最初主要C++函数的文件的名称),其中包含以下行:
int Ynano();
Run Code Online (Sandbox Code Playgroud)在Y.cpp和Y_NANO.cpp中包含新标头:
#include "Y_NANO.h"
Run Code Online (Sandbox Code Playgroud)Ynano()从mainY.cpp中的函数调用该函数.
要在Visual Studio中编译,只需将所有源文件放在同一文件夹中并创建一个新项目.在Unix中,我按照这里给出的步骤操作.
这些步骤只会使程序一起运行,而不会在它们之间传递信息.要在程序之间传递信息,有必要包含一些参数作为参数Ynano(),但这是另一个故事.
一些最终评论:
1)我应该用我的C头文件包装
extern "C" {}吗?2)我应该
extern "C"在我的C函数中使用吗?
仅当您计划#include从某些C++源文件中获取C头时,即,如果您想从C++代码中调用其中一个C函数.使C头文件在C++中可用的典型方法是这样的:
#ifndef MY_C_HEADER_H
#define MY_C_HEADER_H
#ifdef __cplusplus
extern "C" {
#endif
/* All the original content of the C header */
#ifdef __cplusplus
}
#endif
#endif
Run Code Online (Sandbox Code Playgroud)
如果您不想修改标头,那么在将其extern "C"包含在C++源文件中时,也可以简单地从标头外部应用它:
// in my_source.cpp (or some C++ header file):
extern "C" {
#include "my_c_header.h"
}
Run Code Online (Sandbox Code Playgroud)
注意:完全不建议使用该解决方案,也不是一个长期/可维护的解决方案,它只是一个快速而肮脏的"只是让它工作"的解决方案经常失败,但有时可行,取决于C的方式标题看起来像(C标题不需要包含许多其他标题,一般不应该,但有些作者没有常识这样做).
原因extern "C"是禁用C++名称修改,即告诉编译器应该编译函数以对应于未损坏的符号和/或应该在符号表中查找未损坏的(当链接到它们时).因此,规则很简单,任何想要编译成可以从C代码(或任何其他语言)调用的库的C++函数都需要声明为extern "C".您在C++代码中调用但链接到从C(或任何其他语言)编译的库的任何函数声明也必须如此extern "C".
3)或者我应该在我的C++文件中使用extern"C"?(标题?函数?所有这些?还是只需要从C程序调用的那些?)
如果要从C代码中调用某些C++函数,则必须extern "C"在编译C++代码时声明这些特定函数.在声明这些函数的C头文件中(为了从C代码调用它们),不需要extern "C"(它总是隐含在C中).
4)理解我不能有两个'主要'功能.我可以简单地重命名我的C++'main'函数吗?
两个主要功能的目的是什么?这是不允许的,没有用.你仍然可以只有一个"程序",一个开始和一个结束,即一个主要功能.你必须选择一个主要功能,并添加你想要的任何额外步骤(调用其他库).换句话说,您必须"合并"主要功能.
5)在unix中编译时,我是否应该将C(icc)和C++(icpc)编译器用于不同的文件?还是仅仅是C++编译器?
您可以使用C编译器编译C代码和C++编译器来编译C++代码.大多数构建系统(cmake,make等)都会自动执行此操作.从技术上讲,你可以尝试使用C++编译器编译C代码,但是不要指望它能够立即工作,甚至不容易让它工作,不值得恕我直言.
6)将我的主要功能从C转换为C++是否可以选择(简化操作)?
这是一个选择.包含C main函数的源文件看起来比较简单,它包含一个C头文件并且具有相当简单的主函数.如果是这样,在C++编译器上编译就不难了(除非它包含的C头是很多其他C头,这是不好的做法,但很可能).您将需要使用extern "C" { }如上所示的C头文件包含.然后,您可以尝试在C++编译器中编译它(仅包含main函数的源文件),并使用C编译器编译其余的C代码,然后将整个事物链接在一起.如果它可以立即工作,那么很好,您可以开始将C main函数与来自其他库的C++ main函数合并,您将会很高兴.
否则,通常的选择是弄清楚你需要C++代码做什么.然后,使用C++库在C++中创建一个C友好函数(没有类等)来完成这些工作.然后,使用说明extern "C"符(在C++ only(__cplusplus)下编译时)创建声明该函数的头文件,并确保此头不包含任何其他C++头(不是标准头,而不是C++库中的任何其他头) ).最后,在您拥有main函数的C源代码中,包含该头文件并在main函数中调用您需要的函数.将整个事物连接在一起,它应该工作.
7)如果我不需要在两个程序之间传递课程信息,我是否需要对它们做任何事情?
不会.只要您不包含C代码中的任何C++标头(编译器不会接受它),C代码就不会意识到类甚至存在.所以,这里没有危险.
8)你建议以什么顺序解决这个问题?(例如,首先将我的C程序编译为C++编译器;其次,将两个代码编译在一起,没有链接;第三,链接代码;第四,在C++中重命名main并通过我的C代码"调用";第五,实现传输信息?)
当然,第一步是确保您可以单独编译.第二步是查看是否可以使用C++编译器编译C程序的主函数(仅主函数)(如上所述).如果成功,则开始将C++主函数中的元素合并到新的"合并"主函数中.如果不成功,请按照我刚才提到的步骤操作.
9)最后,每个程序中都有一些宏,它们是重复的(同名,相同的实现).与此有冲突吗?我应该只保留一组宏吗?
MACRO ......这很难说.如果您按照创建可以从C main函数调用的C++函数的过程,那么您基本上可以完全隔离这两个库,即它们是单独编译并在之后链接在一起的.在这种情况下,冲突的MACRO没有问题(但是如果某些函数extern "C"在C++库中,可能会有相同名称的函数).如果您尝试将主要功能合并到一个C++主函数中,则可能会出现一些问题,即C头和C++头之间存在冲突的宏,这些头将包含在一起.