c++ - 结合大型 C 和 C++ 程序

标签 c++ c unix visual-studio-2008 icc

我已经阅读了几种组合 C 和 C++ 代码的方法,但是,我仍然对如何进行我的案例感到困惑。这是我的问题:

我有相对大量的 C 代码(由各种 .c.h 文件组成)用于模拟有限和离散元素中的实体。这段代码有一个相对简短和简单的主函数,带有 for循环中按顺序调用各种其他函数(来自其他文件)。此代码在 Unix(icc 编译器)和 Visual Studio 中编译时都可以正常工作。

我在 C++ 中有其他代码可以解决分子动力学相互作用。此代码还包含各种文件,并且在 Unix(icpc 编译器)和 VS 中都可以正常运行。两者都是具有自己的输入和输出文件集的独立程序。

我需要做什么是以这样的方式运行这两个程序,即我的 C 程序在其主循环中“调用”C++ 代码。有些信息需要在两个代码之间双向传递,可能是数组(或指针)的形式。

什么是最简单的方法来做到这一点?

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

  • 我应该用 extern "C" {} 包装我的 C 头文件吗? ?
  • 我应该使用 extern "C"在我的 C 函数中?
  • 或者我应该使用 extern "C"在我的 C++ 文件中? (头文件?函数?所有这些?还是只有那些我需要从 C 程序调用的?)
  • 在明白我不能有两个main职能。我可以简单地重命名我的 C++ main功能?
  • 在 unix 中编译时,我是否应该对不同的文件同时使用 C (icc) 和 C++ (icpc) 编译器?还是只是 C++ 编译器?
  • 是否可以选择(以简化事情)转换我的 main从 C 到 C++ 的函数?
  • 如果我不需要在两个程序之间传递类的信息,我需要对它们做些什么吗?
  • 您建议按照什么顺序解决这个问题? (例如,首先让我的 C 程序由 C++ 编译器编译;第二,将两个代码一起编译,没有链接;第三,链接代码;第四,在 C++ 中重命名 main 并让我的 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();
    }
    

    答复后 24 小时更新

    我按照提供的答案遵循了建议,结果我的问题的解决方案比原先想象的要简单得多(尽管在让它工作之前我确实必须探索几个选项)。最好的部分是它适用于 Unix 和 Visual Studio。以下是我采取的步骤的总结:
  • 将我的主 C 文件转换为 C++。为此,重命名包含 main 的文件。我的 C 代码的函数带有 .cpp 扩展名(从 Y.c 更改为 Y.cpp)并更改 main 的开头功能来自:
    main(argc, argv)
      INT argc; char **argv;
    


    int main(int argc,char **argv)
    

    为了使其 C++“友好”。 (注意:我知道将文件重命名为 .cpp 不是必需的,但我认为为了清楚起见最好这样做)。
  • 包裹我所有的 C 头文件
    #ifdef __cplusplus
    extern "C" {
    #endif
    

    一开始,和
    #ifdef __cplusplus
    }
    #endif
    

    最后。
  • 更改我的名称 main C++ 函数和(暂时)不使用参数。我给它取名 int Ynano() .
  • 使用以下行创建一个名为 Y_NANO.h 的新头文件(Y_NANO.cpp 是包含最初主要 C++ 函数的文件的名称):
    int Ynano();
    
  • 在 Y.cpp 和 Y_NANO.cpp 中包含新标题:
    #include "Y_NANO.h"
    
  • 调用函数 Ynano()来自 main Y.cpp 中的函数。
  • 要在 Visual Studio 中编译,只需将所有源文件放在同一文件夹中并创建一个新项目。在 Unix 中,我按照给定的步骤 here .

  • 这些步骤只会使程序一起运行,而不会在它们之间传递信息。为了在程序之间传递信息,需要包含一些参数作为 Ynano() 的参数。 ,但那是另一回事了。

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

    1) Should I wrap my C header files with extern "C" {}?

    2) Should I use extern "C" in my C functions?



    仅当您打算 #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
    

    如果不想修改header,也可以简单的应用extern "C"将其包含在 C++ 源文件中时,从头文件的外部:
    // in my_source.cpp (or some C++ header file):
    
    extern "C" {
    
    #include "my_c_header.h"
    
    }
    

    注意:根本不推荐使用该解决方案,也不是长期/可维护的解决方案,它只是一个快速而肮脏的“让它工作”的解决方案,经常失败,但有时会奏效,具体取决于 C header 看起来像(C header 不需要包含许多其他 header ,一般不应该包含,但有些作者没有这样做的常识)。
    extern "C"的原因是禁用 C++ 名称修改,即告诉编译器应该编译函数以对应于未修改的符号和/或应该在未修改的符号表中查找(链接到它们时)。因此,规则很简单,您想要编译成可从 C 代码(或任何其他语言)调用的库的任何 C++ 函数都需要声明为 extern "C" .您在 C++ 代码中调用但链接到从 C(或任何其他语言)编译的库的任何函数声明必须是 extern "C"以及。

    3) Or should I use extern "C" in my C++ files? (headers? functions? all of them? or only those I need to call from the C program?)



    如果你想从你的 C 代码中调用一些 C++ 函数,那么这些特定的函数必须声明为 extern "C"编译该 C++ 代码时。在声明这些函数的 C 头文件中(为了从 C 代码调用它们),不需要 extern "C" (它总是隐含在 C 中)。

    4) In understand I can not have two 'main' functions. Can I simply rename my C++ 'main' function?



    两个主要功能的目的是什么?这是不允许的,也没有用。您仍然可以只拥有一个开始和结束的“程序”,即一个主要功能。您必须选择其中一个主要功能,并添加您想要的任何额外步骤(调用另一个库)。换句话说,您必须“合并”主要功能。

    5) When compiling in unix, should I use both C (icc) and C++ (icpc) compilers for different files? or just the C++ compiler?



    您使用 C 编译器编译 C 代码,使用 C++ 编译器编译 C++ 代码。无论如何,大多数构建系统(cmake、make 等)都会自动执行此操作。从技术上讲,您可以尝试使用 C++ 编译器编译 C 代码,但不要指望它立即工作,甚至根本无法轻松使其工作,恕我直言,不值得付出努力。

    6) Could it be an option (to simplify things) to convert my main function from C to C++?



    那是一种选择。你的包含 C main 函数的源文件看起来比较简单,它包含一个 C 头文件并且有一个相当简单的 main 函数。如果是这样,这将不难在 C++ 编译器上进行编译(除非它包含的 C 头文件是许多其他 C 头文件,这是不好的做法,但很可能)。您需要使用 extern "C" { } 来包装包含的 C 头文件。如上图所示。然后,您可以尝试在 C++ 编译器中编译它(仅包含 main 函数的源文件),并使用 C 编译器编译其余的 C 代码,然后将整个内容链接在一起。如果立即生效,那就太好了,您可以开始将该 C main 函数与来自其他库的 C++ main 函数合并,然后就可以了。

    否则,通常的选择是弄清楚您需要 C++ 代码做什么。然后,使用 C++ 库在 C++ 中创建一个 C 友好的函数(无类等)来执行这些操作。然后,创建一个声明该函数的头文件,使用 extern "C"说明符(仅在 C++ 下编译时 ( __cplusplus )),并确保此头文件不包含任何其他 C++ 头文件(不是标准头文件,不是来自 C++ 库的任何其他头文件)。最后,在您拥有 main 函数的 C 源代码中,包含该头文件并从 main 函数中需要它的位置调用该函数。将整个事情联系在一起,它应该可以工作。

    7) If I don't need to pass information of classes between the two programs, do I need to do anything about them?



    不。只要您不包含来自 C 代码的任何 C++ 头文件(编译器无论如何都不会接受),C 代码甚至不知道类存在。所以,这里没有危险。

    8) In what order do you suggest this problem to be tackled? (e.g. first have my C program compiled by C++ compiler; second, compile both codes together with no links; third, link the codes; fourth, rename main in C++ and have it "called" by my C code; fifth, implement the transfer of information?)



    当然,第一步是确保您可以分别编译两者。第二步是看是否可以用C++编译器(如上所述)编译C程序的主函数(仅主函数)。如果成功,开始将来自 C++ 主函数的元素合并到新的“合并”主函数中。如果不成功,请按照我刚才提到的步骤操作。

    9) Finally, there are some macros in each program, which are repeated (same name, same implementation). Is there a conflict with this? Should I only keep one set of macros?



    宏……这很难说。如果您按照创建可以从 C 主函数调用的 C++ 函数的过程进行操作,那么您基本上可以完美地隔离两个库,即它们被分别编译并在之后链接在一起。在这种情况下,MACRO 冲突不会有问题(但可能存在同名的函数,如果在 C++ 库中有些是 extern "C")。如果您尝试将主函数合并到一个 C++ 主函数中,您可能会遇到一些问题,即 C 头文件和 C++ 头文件之间的 MACRO 冲突,它们将被包含在一起。

    关于c++ - 结合大型 C 和 C++ 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17301704/

    相关文章:

    c - wait(null) and wait(&status) C语言与状态

    c++ - 是否可以在 C/C++ 中声明全局二维数组?

    c++ - 重载虚函数并通过指向基类的指针调用派生函数

    C++:cout 语句使我的程序失控?

    c - Turbo C - Scanf 只接受一个字符

    linux - 为什么 pidstat 没有反射(reflect)我使用任务集对 CPU 亲和性所做的更改?

    c++ - 将父类的 const 引用转换为派生的子对象

    c - 如何将输出打印成表格形式?

    c - 打印txt文件的校验和而不打印文件路径

    json - 如何在 shell 脚本中漂亮地打印 JSON?