Я читал о нескольких методах комбинирования кодов C и С++, однако я все еще запутался в том, как действовать в моем случае. Вот моя проблема:
У меня относительно большое количество кода С (состоящее из различных файлов .c
и .h
), которое используется для моделирования твердых тел в конечных и дискретных элементах. Этот код имеет относительно короткую и простую основную функцию с циклом for
, в котором различные другие функции (из других файлов) называются последовательно. Этот код отлично работает при компиляции как в Unix (icc-компилятор), так и в Visual Studio.
У меня есть другой код на С++, который решает взаимодействие молекулярной динамики. Этот код также состоит из различных файлов и отлично работает как в Unix (icpc-компилятор), так и в VS. Оба являются автономными программами со своим собственным набором входных и выходных файлов.
Что мне нужно сделать - это запустить обе программы таким образом, чтобы моя программа C вызывала код С++ в своем основном цикле. Некоторая информация должна передаваться в обоих направлениях между двумя кодами, которые могут быть в виде массивов (или указателей).
Каков самый простой способ сделать это?
В частности, у меня есть несколько вопросов, основанных на рекомендациях, которые я прочитал:
- Должен ли я обернуть файлы заголовков C с помощью
extern "C" {}
? - Должен ли я использовать
extern "C"
в моих C-функциях? - Или мне следует использовать
extern "C"
в моих файлах на С++? (заголовки? функции "все из них" или только те, которые мне нужно вызвать из программы C?) - В понимании я не могу иметь две функции
main
. Можно ли просто переименовать мою С++main
функцию? - При компиляции в unix я должен использовать компиляторы C (icc) и С++ (icpc) для разных файлов? или просто компилятор С++?
- Может ли это быть (упростить) преобразование моей функции
main
из C в С++? - Если мне не нужно передавать информацию о классах между этими двумя программами, нужно ли что-нибудь сделать с ними?
- В каком порядке вы предлагаете решить эту проблему? (например, сначала моя программа на языке C, скомпилированная компилятором С++, во-вторых, скомпилируйте оба кода вместе без ссылок, в-третьих, свяжите коды, в-четвертых, переименуйте
main
в С++ и попросите его "вызвать" по моему 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 в С++. Для этого переименуйте файл, содержащий функцию
main
моего C-кода с расширением .cpp(измененным с Y.c на Y.cpp) и измените начало функцииmain
на:main(argc, argv) INT argc; char **argv;
к
int main(int argc,char **argv)
чтобы сделать его "дружественным". (Примечание: я понимаю, что переименование файла на .cpp не является существенным, но я думаю, что лучше сделать это для ясности).
-
Оберните все мои файлы заголовков C с помощью
#ifdef __cplusplus extern "C" { #endif
в начале и
#ifdef __cplusplus } #endif
в конце.
-
Измените имя моей функции
main
С++ и (временно) не используйте аргументы. Я назвал егоint Ynano()
. -
Создайте новый заголовочный файл с именем Y_NANO.h(Y_NANO.cpp - это имя файла, содержащего исходную основную функцию С++) с помощью строки:
int Ynano();
-
Включите новый заголовок как в Y.cpp, так и в Y_NANO.cpp:
#include "Y_NANO.h"
-
Вызвать функцию
Ynano()
из функцииmain
в Y.cpp. -
Чтобы скомпилировать в Visual Studio, просто поместите все исходные файлы в одну и ту же папку и создайте новый проект. В Unix я выполнил шаги, указанные здесь.
Эти шаги позволят программам работать вместе, без передачи информации между ними. Для передачи информации между программами необходимо включить некоторые параметры в качестве аргументов Ynano()
, но это другая история.
Некоторые заключительные комментарии:
- Проблема с повторением макросов в разных заголовочных файлах, похоже, не является реальной проблемой, поскольку ни один файл не включает оба заголовка (мне не нужно было ничего делать).
- Спасибо всем, кто дал ответы. Они были действительно полезны. Выбранный ответ был выбран на основе полноты, но другие были так же хороши. Я надеюсь, что нить помогает другим выполнять свою работу, так как многие другие темы помогли мне сделать то же самое.