结合大型C和C++程序

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++代码的方式运行这两个程序.一些信息需要在两个代码之间双向传递,这两个代码可以是数组(或指针)的形式.

最简单的方法是什么?

特别是,根据我读过的建议,我有多个问题:

  1. 我应该用我的C头文件包装extern "C" {}吗?
  2. 我应该extern "C"在我的C函数中使用吗?
  3. 或者我应该extern "C"在我的C++文件中使用?(标题?函数?所有这些?还是只需要从C程序调用的那些?)
  4. 在理解我不能有两个main功能.我可以简单地重命名我的C++ main函数吗?
  5. 在unix中编译时,我是否应该将C(icc)和C++(icpc)编译器用于不同的文件?还是仅仅是C++编译器?
  6. 它可以是一个选项(简化事情)将我的main函数从C 转换为C++吗?
  7. 如果我不需要在两个程序之间传递类的信息,我是否需要对它们做任何事情?
  8. 您建议以什么顺序解决此问题?(例如,首先让我的C程序由C++编译器编译;第二,编译两个代码而没有链接;第三,链接代码;第四,main在C++中重命名并由我的C代码"调用";第五,实现传输信息?)
  9. 最后,每个程序中都有一些宏,它们是重复的(同名,相同的实现).与此有冲突吗?我应该只保留一组宏吗?

抱歉,长文和多个问题.我对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.以下是我采取的步骤摘要:

  1. 将我的主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并不重要,但我认为为了清晰起见,最好这样做).

  2. 用我的所有C头文件包装

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    Run Code Online (Sandbox Code Playgroud)

    在开始时,和

    #ifdef __cplusplus
    }
    #endif
    
    Run Code Online (Sandbox Code Playgroud)

    在末尾.

  3. 更改我的mainC++函数的名称和(暂时)不使用参数.我把它命名了int Ynano().

  4. 创建一个名为Y_NANO.h的新头文件(Y_NANO.cpp是包含最初主要C++函数的文件的名称),其中包含以下行:

    int Ynano();
    
    Run Code Online (Sandbox Code Playgroud)
  5. 在Y.cpp和Y_NANO.cpp中包含新标头:

    #include "Y_NANO.h"
    
    Run Code Online (Sandbox Code Playgroud)
  6. Ynano()mainY.cpp中的函数调用该函数.

  7. 要在Visual Studio中编译,只需将所有源文件放在同一文件夹中并创建一个新项目.在Unix中,我按照这里给出的步骤操作.

这些步骤只会使程序一起运行,而不会在它们之间传递信息.要在程序之间传递信息,有必要包含一些参数作为参数Ynano(),但这是另一个故事.

一些最终评论:

  • 在不同的头文件中重复宏的问题似乎不是一个真正的问题,只要没有文件包含两个头文件(我不需要对此做任何事情).
  • 感谢所有提供答案的人.他们真的很有帮助.选择的答案是在完整性的基础上选出的,但其他答案也同样好.我希望这个帖子可以帮助其他人完成他们的工作,因为许多其他线程帮助我做同样的事情.

Mik*_*son 7

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++头之间存在冲突的宏,这些头将包含在一起.

  • `extrern"C"{#include <my.h>}`是一个很大的禁忌.标题通常包括其他标题,包括库,标准,将它们放在那个块中是坏的. (2认同)