12

I have read about several methods to combine C and C++ codes, however, I'm still confused on how to proceed in my case. Here is my problem:

I have a relatively large amount of C code (consisting of various .c and .h files) which is used to model solids in finite and discrete elements. This code has relatively short and simple main function with a for loop in which various other functions (from other files) are called sequentially. This code works fine when compiled in both Unix (icc compiler) and Visual Studio.

I have other code in C++ that solves molecular dynamics interactions. This code also consists of various files and runs fine in both Unix (icpc compiler) and VS. Both are stand alone programs with their own input and output set of files.

What I need to do is to run both programs in such way that my C program "calls" the C++ code in its main loop. Some information needs to be passed both ways between the two codes, which may be in the form of arrays (or pointers).

What is the simplest way to do this?

In particular, I have multiple questions based on recommendations I have read:

  1. Should I wrap my C header files with extern "C" {}?
  2. Should I use extern "C" in my C functions?
  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?)
  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?
  6. Could it be an option (to simplify things) to convert my main function from C to C++?
  7. If I don't need to pass information of classes between the two programs, do I need to do anything about them?
  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?)
  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?

Sorry for the long text and multiple questions. I am relatively new to C and even newer to C++, so even my vocabulary on these programs is limited.

Thanks for the help. Any hints will be appreciated. If you need additional information, please let me know.

Here is the 'main' function of my C code:

#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();
}

UPDATE 24 HOURS AFTER ANSWERS

I followed the recommendations as per provided answers and the solution to my problem turned out to be much simpler than originally thought (although I did have to explore several options before getting it working). The best part is that it works in both Unix and Visual Studio. Here is the summary of steps I took:

  1. Convert my main C file to C++. For this, rename the file containing the main function of my C code with a .cpp extension (changed from Y.c to Y.cpp) and change the beginning of the main function from:

    main(argc, argv)
      INT argc; char **argv;
    

    to

    int main(int argc,char **argv)
    

    in order to make it C++ 'friendly'. (Note: I understand renaming the file to .cpp is not essential, but I think it's better to do it for clarity).

  2. Wrap all my C header files with

    #ifdef __cplusplus
    extern "C" {
    #endif
    

    at the beginning, and

    #ifdef __cplusplus
    }
    #endif
    

    at the end.

  3. Change the name of my main C++ function and (temporarily) use no arguments. I named it int Ynano().

  4. Create a new header file called Y_NANO.h (Y_NANO.cpp is the name of the file containing the originally main C++ function) with the line:

    int Ynano();
    
  5. Include the new header in both Y.cpp and Y_NANO.cpp:

    #include "Y_NANO.h"
    
  6. Call the function Ynano() from the main function in Y.cpp.

  7. To compile in Visual Studio, simply put all the source files in the same folder and create a new project. In Unix, I followed the steps given here.

These steps will only make the programs run together, with no transfer of information between them. To transfer information between the programs, it is necessary to include some parameters as arguments of Ynano(), but that's another story.

Some final comments:

  • The problem of having repeated macros in different header files does not seem to be a real problem, as long as no file includes both headers (I didn't need to do anything about this).
  • Thanks to all who provided answers. They were really helpful. The chosen answer was selected on the basis of completeness, but others were just as good. I hope the thread helps others to do their job, as many other threads have helped me to do the same.
Leonardo Trivino
  • 295
  • 1
  • 4
  • 11
  • Style note: Backticks are not for emphasis. :P They're for highlighting code and other verbatim text output by, or entered into, a computer. – cHao Jun 25 '13 at 15:59
  • @cHao, thanks for clearing that up. I'm relatively new here, so I wasn't sure about formatting :-P – Leonardo Trivino Jun 25 '13 at 17:02

5 Answers5

9

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

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

Only if you plan to #include the C headers from some C++ source files, i.e., if you want to call one of the C functions from your C++ code. The typical way to make a C header file usable in C++, is like this:

#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

If you don't want to modify the header, it is also possible to simply apply the extern "C" from the outside of the header when including it in a C++ source file:

// in my_source.cpp (or some C++ header file):

extern "C" {

#include "my_c_header.h"

}

NOTE: Doing that solution is not at all recommended nor is it a long-term / maintainable solution, it is just a quick-and-dirty "just make it work" solution that often fails, but sometimes works, depending on how the C headers look like (C headers don't need to include many other headers, and shouldn't in general, but some authors don't have the common sense to do so).

The reason for extern "C" is to disable C++ name-mangling, i.e., tell the compiler that the functions should be compiled to correspond to un-mangled symbols and/or should be looked up in the symbol table un-mangled (when linking to them). So, the rule is simple, any C++ functions that you want to compile into a library that would be callable from C code (or any other language for that matter) needs to be declared as extern "C". And any function declarations that you which to call in C++ code but links to a library compiled from C (or any other language) must be extern "C" as well.

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?)

If you want to call some C++ functions from your C code, then those specific functions will have to be declared as extern "C" when compiling that C++ code. In the C header file that declares those functions (for the purpose of calling them from the C code), there is no need for extern "C" (it is always implied in C).

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

What would be the purpose of two main functions? It is not allowed and not useful. You can still just have one "program" with one start and one end, i.e., one main function. You'll have to pick one of the main functions, and add to it whatever extra steps you want (calling the other library). In other words, you have to "merge" the main functions.

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

You use the C compiler to compile the C code and a C++ compiler to compile the C++ code. Most build systems (cmake, make, etc.) will automatically do that anyways. Technically, you could try and compile the C code using the C++ compiler, but don't expect it to work right away or even be easy at all to get it working, not worth the effort IMHO.

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

That is an option. You source file containing the C main function seems relatively simple, it includes one C header file and has a fairly simple main function. If so, this won't be hard to get to compile on a C++ compiler (unless the C header that it includes is a lot of other C headers, which is bad practice, but likely). You will need to wrap the C header file inclusion with the extern "C" { } as shown above. Then, you can just try to compile it (only the source file containing the main function) in a C++ compiler, and the rest of the C code with the C compiler, and then link the whole thing together. If that works right away, then great, you can start to merge that C main function with the C++ main function from the other library, and you will be good to go.

Otherwise, the usual option is to figure out what you need the C++ code to do. Then, create a C-friendly function (no classes, etc.) in C++ that does these things, using the C++ library. Then, create a header file that declares that function, with the extern "C" specifier (when compiling under C++ only (__cplusplus)), and make sure that this header does not include any other C++ header (not standard headers, not any other headers from the C++ library). And finally, in your C source code, where you have the main function, include that header and call that function(s) from where you need it in the main function. Link the whole thing together and it should work.

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

No. As long as you don't include any C++ header from the C code (which the compiler won't accept anyways), the C code is not aware that classes even exist. So, there is no danger here.

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?)

First step is, of course, to make sure you can compile both separately. Second step is to see if it is possible to compile the C program's main function (only the main function) with a C++ compiler (as explained above). If successful, start incorporating elements from the C++ main function into that new "merged" main function. If unsuccessful, follow the steps that I just mentioned.

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?

MACROs... that's hard to tell. If you follow the procedure of creating a C++ function that can be called from the C main function, then you essentially have a perfect isolation of both libraries, i.e., they are compiled separately and linked together after. In that case, there will be no problem with conflicting MACROs (but there might be with functions of the same name, if some are extern "C" in the C++ library). If you try to merge the main functions into one C++ main function, you might have some problems with conflicting MACROs between the C headers and C++ headers which will be included together.

Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
  • 2
    the `extrern "C" { #include }` is a big no-no. headers normally include other headers including library, standard, putting them in that block is bad. – Balog Pal Jun 25 '13 at 16:31
  • @BalogPal: +1, you're right, it's a last resort more than anything else. When you just want it to work, it's worth a try. But it's not a long term / maintainable solution that's for sure. – Mikael Persson Jun 25 '13 at 16:38
  • @MikaelPersson thanks for your answer. Just a comment: **4.** Perhaps I wasn't clear on this question. Currently, both C and C++ programs are stand alone, so each has its own main function. What I meant to ask was if I should rename my current C++ main function as something else, precisely to be able to call it from my C code. – Leonardo Trivino Jun 25 '13 at 17:42
  • @LeonardoTrivino Yes, you can certainly rename the main function in your C++ code to something else, mark it as `extern "C"` and call it from the C code. I just don't see much use for that except as practice. It will be more practical to create a different function with direct in-memory parameters (as array pointers, etc.) instead of the (argc, argv) params. Otherwise, it is no different from simply executing the C++ program with `system("/path/to/the/cpp/project/my_cpp_program");` from the C code. – Mikael Persson Jun 25 '13 at 21:04
2
  1. yes but wrapped like explained here : Combining C++ and C - how does #ifdef __cplusplus work?
  2. not needed if they are in the header file. If they are not then you need a forward extern declaration in your C++ files if it needs it and yes with extern "C"
  3. This is not always possible because classes and some C++ typical stuff just does not work in C. But if the C++ code is really just C, it will work too. Using C in C++ is a lot easier than the reverse.
  4. What point is it to rename the second main fnction ? It will not be called, you can have only one main function
  5. you can choose to rename you c files into C++ and start to compile everything with C++. This would resolve your linkage problems with the extern "C" stuff and is what I would do in the first place. Otherwise C is compiled with a C compiler and C++ with a C++ compiler. These compilers behave differently of course.
  6. yes of course, your C code might need some rework though. This is what I would do
  7. don't think so. Then again, there don't seem to be any dependencies ? How can this be ?
  8. does not matter, start compiling, then fix linker problems
  9. might have conflicts if you include 2 header files containing the same macro. Compiler will complain with a redefinition.
Community
  • 1
  • 1
Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
  • normally you gave compiler or makefile magic to just force C or C++ compile, renaming files is not strictly necessary. – Balog Pal Jun 25 '13 at 16:28
  • @philip thanks for your answer. A few comments: **4.** Perhaps I wasn't clear on this question. Currently, both C and C++ programs are stand alone, so each has its own main function. What I meant to ask was if I should rename my current C++ main function as something else, precisely to be able to call it from my C code. **7.** I wasn't accurate on this point. There are some arrays that currently exist in the C program and need to be passed and modified by the C++ program. What I meant is that there are no classes or objects from C++ that will need to be passed on to the C program. – Leonardo Trivino Jun 25 '13 at 17:26
  • @Balog Pal : I know, but compiling C++ files that have a c extension is not a good idea. It's confusing. – Philip Stuyck Jun 25 '13 at 19:22
  • @LeonardoTrivino : You can just call the renamed main from the other main. – Philip Stuyck Jun 25 '13 at 19:23
1

Summary:

I think you can just compile your C main() in a separate CPP compilation unit and then "extern C" all your C function definitions. Calling from CPP to C is easy. The other way around is a little more cumbersome as you will have to create "...a C API for exposing the functionality of your C++ code..." - see How to call C++ function from C?

EDIT: Above edited thanks to feedback from Mikael (see comments). Looking at it, I think C++ to C is still generally easier if the C++ code takes advantage of C++ specific features like objects overloading, etc as then it may need C API wappers (see above link). In this case, as Mikael points out, it isn't really the case so either way is as easy / hard...

Note: Combine both your main()'s into the one CPP function.

Detail:

run both programs in such way that my C program "calls" the C++ code

That's usually a little difficult I'm afraid. C++ does something called name mangling, so calling a C++ function from C is difficult to do in a portable fashion, unless you've made a C wrapper (see above link). The reason being is that the CPP compiler (internally without you seeing this) re-writes the function names and includes such things as the parameter types, usually as a suffix to the name, so that it can do things like function overloading. The C compiler doesn't do this because function overloading isn't possible in C.

I'd say it would be better to run your main from a C++ module and call your C functions from there... that way you get around the name mangling issue.

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

Yes, it's important in the C header files to wrap all function definitions with this. Normally you'll see something like

#ifndef HEADER_FILE_NAME
#define HEADER_FILE_NAME
#ifdef __cplusplus
   extern "C" {
#endif
/// FILE CONTENTS
#ifdef _cplusplus
   }
#endif
#endif // HEADER_FILE_NAME

What this does is tell the CPP compiler that these function names should not be mangled. This way the correct symbol names will be used when linking with the C functions.

When compiling a CPP module __cplusplus should be defined but when compiling a C module it should not. This means that when the CPP module includes your C header file, it will not mangle the function names and can therefore call the C functions correctly.

Or should I use extern "C" in my C++ files?

The extern "C" just tells the compiler that the function has C language linkage so the generated symbol won't be mangled. So I think, if it is a function that has not been overloaded then doing this (in the H file for the function definition) will prevent the function name being mangles so you'll be able to call it from C. However, if you extern "C" a class for example, that will still have C++ linkage, same for class member functions etc... depends if you use these or not... doesn't look like it from your code sample.

In understand I can not have two main functions. Can I simply rename my C++ main function? Could it be an option (to simplify things) to convert my main function from C to C++?

Yes, I think this is the best option. If only the main() function needs to call both types of code then you're fine. The one main() function written in a CPP compilation unit.

If however there is a C module that needs to call a C++ module then you will need to consider compiling that as a CPP file or making sure that the CPP function is extern "C" and isn't overloaded.

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?

If the macros are defined in C/CPP files then you're OK. If they are in header files then there could be a conflict if one file includes two header files which both contain the same macro. In either case i would recommend taking all common macros out into shared header files so that there is only one instance of the macro... much more maintainable... go with the "do not repeat yourself" mantra :)

I haven't addressed all your points, but hope this is enough to get you started :)

Community
  • 1
  • 1
Jimbo
  • 4,352
  • 3
  • 27
  • 44
  • I don't agree that calling C++ from C is hard. Both are just as easy / hard. In both cases, you need a C interface with some header that is ready to be included from the other language. Choosing which calls which is mostly a matter of the relationship of the code (who needs who, who controls the process vs. who delivers a service). In this case, it seems that the C++ library is the one helping the C library. – Mikael Persson Jun 25 '13 at 16:52
  • @Jimbo Thanks for your answer. About the macros point, they are in two header files, but I don't think there will be any C/CPP files including both of these header files (unless my main function needs to call both of them, which I'm not sure yet if it's a requirement). – Leonardo Trivino Jun 25 '13 at 17:32
  • @Mikael: Had a bit of a dig in response to your comment and agreed to some exent... I think C++ to C is still generally easier as the otherway around, if the C++ code takes advantage of C++ specific features like overloading etc. In this case, as you point out, it isn't reallly the case so either way is as easy / hard. Thanks for the feedback :) – Jimbo Jun 26 '13 at 09:03
  • @Leonardo: Some updates based on Mikaels comments. In response to your comment, if the macros are identical then from a maintenance point of view, I still think one file is better. If you change macro A in file X to solve a bug for example, you have to change it in file Y as well... much easier to have it all in one place :) – Jimbo Jun 26 '13 at 09:07
0

Well, ideally you could compile your C sources as C++ without change in semantics, then just enjoy a uniform system. Depending on the size of your codebase and its shape worth considering as option. Actually it might be less work than fiddling with all those extern "C"-s and fallout.

The next option is cooperation. C++ is designed to play compatible with C, the other direction is not so in theory, but it is in practice -- I expect compilers of the same vendor support cross-talk in all directions.

Most important thing to be aware is that if you add C++ then all your system is considered C++, so you must heed the one definition rule, have your main from C++, etc. You compile the C sourced with the C compiler and treat them as guest... You must tune the compiler options to be compatible and insturment all the headers that are shared between systems. That usually means using those conditionals, extern "C", typedefing structs to their own names and so on.

With cross-calls look after exceptions. In some systems they must not cross C/C++ boundary. In others they can, but you need to tweak options to make it work well.

In the first pass you need only to make the stuff execute as before. For suggestions of later refactorings there are good questions here on SO and at other places.

Balog Pal
  • 16,195
  • 2
  • 23
  • 37
-1

I'll tell you the correct answer and you're probably not going to like it. Without knowing all the specifics of your code, it sounds like you need to do some heavy refactoring.

In an ideal world, when you write your application, it should be written in such a way that the implementation is done as a formal API and the main() translates/parses the command-line arguments into appropriate calls into the API. If done correctly, the file that has the main() routine is only needed to build the executable for its task.

Better still, the implementation would be built as a library and a set of headers for using that library.

Then your task would not be blenderizing two executables, but instead building a new application that calls two different libraries.

The reason that you're not going to like it is that this is time-consuming. It's time consuming to do the correct design to make a library rather than cobble together a few classes/functions to do the task de jour, but unless your existing code is very well-organized as it is, this is meant to save your time dealing with code issues that will eventually crop up.

What I would do if I were you is first figure out exactly how each application works. Step through them. See where the code goes and get its theory of operations into your head. Doing that will allow you to package or repackage it in a suitable way.

plinth
  • 48,267
  • 11
  • 78
  • 120
  • 1
    There is plenty of examples of code that is using C and C++ together and not using libraries at all. Consuming C from C++ is actually pretty easy, the reverse is more problematic. His question about the main is puzzling me however. You can have only one main and only that one will be executed. So if both things need to run, one is going to call the other. If this is the case have the C++ main call the C renamed main function at the end of at the beginning depending on the situation. – Philip Stuyck Jun 25 '13 at 16:03
  • I'm not saying it's not possible, I'm saying that it's not best practice. – plinth Jun 25 '13 at 17:32
  • @plinth Well, first thanks for your answer. Second, you are right that I'm not liking it. If I understand correctly, you are suggesting to completely re-design both codes... Well, these are large codes and even though I understand most of the algorithms and flow of information, I do not believe a re-design is the right way to go. These are engineering codes and in fact there are many things I need to test before even claiming that merging them is a good idea (and for this I actually need to merge them in the first place!). Re-design may be considered at a later stage. – Leonardo Trivino Jun 25 '13 at 18:20
  • It is not bad practice either. It is actually common practice. But if it were up to me I would compile all legacy C modules with a C++ compiler to avoid all the hastles with linkage specifications and creating extra header files for a C interface of a C++ interface so that it can be used in a C module. Nevertheless, there are plenty o examples where in realtime embedded sw, hardware related modules are in C, whereas the applications on top of them are in C++. As such the dependencies are as such that C++ modules use C includes. No big deal at all. – Philip Stuyck Jun 25 '13 at 20:47
  • "It is not bad practice either. It is actually common practice." Sure - because it's expedient, but it creates all manner of problems when the code contains, say, global variables, improper module dependencies, improper (or no) abstraction, etc. - all common practice in a monolithic application but become a living hell the first time it gets repackaged in a different application that needs multiple separate contexts or multithreading, or... – plinth Jun 26 '13 at 12:11