C++ and other lang how to use both

A couple days ago I decided I was going to attempt to use a different language with c++ (specifically node.js). This resulted in a desperate search on how to integrate the two programs with each other and ended with me doing a really strange redirection thing. Obviously not my first choice. So. How are you supposed to integrate different languages into the same program?


strange code:
1
2
3
4
5
6
7
8
#include <iostream>
#include <fstream>
#include <cstdlib>

int main(){
  system("node >&0 < node.in &");
  std::ofstream nodeComm("node.in");
}


yeah. Not good. So. Any help?
What's wrong with the dead simple solution you've found?
Well.. my ide doesn’t allow me to edit files most of the time, so it doesn’t always work.
Also the only programmer that I know personally started literally gagging at my code, so not a great sign at any time of day.
@highwayman, what do you want to do with your mixed-language programming?

Also, do you want to call node.js from c++ ... or c++ from node.js?
https://nodejs.org/api/addons.html
Do you want to call individual procedures/functions, or make system calls to whole scripts? Are you interfacing compiled languages (like c++) or mixing compiled and scripted languages?
Last edited on
node is multi threaded by default. the 'easy' way to use it with c++ is to call it from c++ where you can control the node segments rigidly. If you try it the other way youll have to assume anything in c++ is thread-safe and that can add complexity, or you can try to force single threaded node but that is more or less defeating the purpose.

The broader answer is it depends on the languages. Its different how you might make 2 compiled languages talk, or 2 interpreted languages work, or a mix of the two (what you are asking here). It also depends on how much you need to couple … a straight handoff can be easy (more or less, your 'program' is a glorified batch file that calls 1 then the other, using a file or something between) and running both at the same time with back and forth can get very challenging.

Ive been impressed with node. For what it is, its rather efficient and is not like so many of the 'you can't do that' minor languages. Unless you need speed badly, you may be better off doing it all in node? Mixing languages is a frustration best avoided if there isn't a very strong reason to do it.
Last edited on
@lastchance I honestly have forgotten by now. The only goal I had by now is to find a way to interface the two. I think it actually started out with SQLite/C++? I can’t access that link because school issued devices/ restrictions, though from the name it definitely looks useful, so I think I might look into it. I was thinking maybe define stuff that’s easier done in node, then call the functions from c++ for whatever reason. I was thinking like calling individual functions and not just running a script.

@jonnin
assume anything in c++ is thread-safe

ho boy. I have basically 0 threading experience in c++. Not a good choice on my part then! 😬 how would you make two compiled langs talk? What’s a batch file? What do you mean by there being even more 'coupling' between programs? Why would you 'couple' more?
@highwayman,
I defer to @jonnin over node.js: I've never used it. However, I have interfaced C/C++ with Fortran (both compiled languages) and used them on a function-by-function basis. From the C++ side it is a simple matter of 'external' statements and from the Fortran side just writing an explicit interface (similar to C++ prototypes) and declaring 'bind(C)' in a few places. Then the linker has to be told to link both Fortran and C libraries, but that is routine.

FWIW, a 'batch' file in its simplest form just contains the sequence of commands that you would issue one after another from the Windows command line, so it just saves (a lot of) time. However, it can be made much more complex with loops and variables like any other programming language. Actually, I use batch files to compile my multi-file programs, because it is much easier than learning 'make'.
ho boy. I have basically 0 threading experience in c++.

that is probably OK, but the node will drive you nuts.
a quick example, in node...
1) get a list of data from a remote source
2) print it.
oops. 2 attempts to print, but 1 isn't done yet, because threads. so it prints 'no data' for #2. This is rookie mistake #1 when learning node -- it will be the first non syntax thing you screw up, I guarantee. Its really easy to forget and bungle this if used to c++ like languages.

on the c++ side, a function is mostly thread safe (barring anything really weird you may have done!) if it does just a few simple things.
- no global variables
-no static variables that matter
- don't call it in parallel on same ref parameters
-Don't print inside functions that do anything else, you want to finely control print statements so not out of order.
If you do the above odds are it will be ok, or easy to fix if you find a problem.

compiled languages are lastchance said... I had a version of fortran that made windows dll files and all I had to do was write the C++ header file and set them to use C style conventions (there are a number of calling convention choices, C is a good one to use, it basically defines who does what to the CPU instruction stack, for the assembly language level coding this has to match so the code works together, eg does the caller or the callee clean up the stack?). Also, details... some languages (most of the interpreted ones) use the same endian on all system while compiled tend to use native, so you have to handle that kind of stuff, or in the case of fortan and C, the 2d arrays are flipped, F is column major, C is row major, so passed 2-d things get transposed and you have to handle this in code. You MUST be aware of little language things like these and make it work. Other things might be index by 1 instead of 0 for first array location, causing off by one in passing arrays around if careless.



Last edited on
highwayman wrote:
how would you make two compiled langs talk?



Here are examples of mixing Fortran and C/C++, with one language containing the main program and the other providing functions to add, subtract and multiply two integers.


In the first case we have C++ calling Fortran; in the second case Fortran calling C++.


Compile/link command for both cases.

With gnu compiler collection (and both C++ and Fortran installed). Note that, if you use the linker for one particular language, then you have to also specify the libraries for the other explicitly.
    g++      -o test.exe     proga.f90 progb.cpp      -lgfortran -lquadmath

OR
    gfortran -o test.exe     proga.f90 progb.cpp      -lstdc++



With intel compilers (and you'll need a licence for the Fortran one; I'm VPN'ing into work)
   ifort -c proga.f90
   cl    -c progb.cpp
   ifort -o test.exe proga.obj progb.obj





Case 1: C++ calls Fortran.
Note that the C++ file requires 'extern' statements, whilst the Fortran file needs an explicit interface to specify the bindings.

proga.f90 (Fortran)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
module help
   use iso_c_binding
   implicit none

contains

   !====================================

   subroutine add( a, b, c ) bind( C, name = "add" )
      integer(c_int), value, intent(in)  :: a, b           ! inputs passed by value
      integer(c_int),        intent(out) :: c
   
      c = a + b
   
   end subroutine add

   !====================================

   integer function subtract( a, b ) bind( C, name = "subtract" )
      integer(c_int), value, intent(in) :: a, b
   
      subtract = a - b
   
   end function subtract

   !====================================

   subroutine multiply( a, b, c ) bind( C, name = "multiply" )
      integer(c_int), intent(in) :: a, b                   ! inputs passed by reference
      integer(c_int), intent(out) :: c
   
      c = a * b
   
   end subroutine multiply

   !====================================

end module help


progb.cpp (C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extern "C" void add( int a, int b, int *c );
extern "C" int subtract( int a, int b );
extern "C" void multiply( int *a, int *b, int *c );


#include <iostream>
using namespace std;

int main()
{
   int a, b;
   int c, d, e;

   cout << "Enter a and b: ";   cin >> a >> b;

   add( a, b, &c );          // Fortran subroutine called as a void function (inputs passed by value)
   d = subtract( a, b );     // Fortran function called as an int function
   multiply( &a, &b, &e );   // Fortran subroutine called as a void function (inputs passed by reference)

   cout << "Sum is " << c << endl;
   cout << "Difference is " << d << endl;
   cout << "Product is " << e << endl;
}




Case 2: Fortran calls C++

proga.f90 (Fortran)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
module help
   use iso_c_binding
   implicit none

   interface

      integer function add( a, b ) bind( C, name = "add" ) ! the "name=" bit is only necessary if you want some upper case
         import c_int
         integer(c_int), value :: a, b                     ! "value" is necessary for pass by value
      end function add

      subroutine subtract( a, b, c ) bind( C, name = "subtract" )
         import c_int
         integer(c_int), value :: a, b                     ! note that a and b are passed by value
         integer(c_int) :: c                               !           c is passed by reference
      end subroutine subtract

      subroutine multiply( a, b, c ) bind( C, name = "multiply" )
         import c_int
         integer(c_int) :: a, b                            ! everything passed by reference
         integer(c_int) :: c                            
      end subroutine multiply

   end interface

end module help


!=======================================================================


program test1
   use help
   implicit none

   integer(c_int) a, b
   integer(c_int) c, d, e

   write( *, * ) "Input a and b"
   read( *, * ) a, b

   c = add( a, b )                     ! calls an external C++ function returning an int
   write( *, * ) "Sum is ", c

   call subtract( a, b, d )            ! calls an external C++ void function
   write( *, * ) "Difference is ", d

   call multiply( a, b, e )            ! calls an external C++ void function
   write( *, * ) "Product is ", e

end program test1


progb.cpp (C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extern "C" int add( int a, int b );
extern "C" void subtract( int a, int b, int &c );
extern "C" void multiply( int &a, int &b, int &c );


int add( int a, int b )
{
   return a + b;
}

void subtract( int a, int b, int &c  )           // input variables passed by value
{
   c = a - b;
}

void multiply( int &a, int &b, int &c )          // input variables passed by reference
{
   c = a * b;
}





Other notes:
Comments are denoted by
// in C++
! in Fortran

Default is to pass by value in C++, but by reference in Fortran, so the interfaces must be made consistent.

You can usually get away with just integer, rather than integer(c_int)

You can get away with just bind(C) rather than bind(C,name="...") provided the C++ routine name is the same and is all lower case.
Last edited on
@laschance external statements? Like with that extern keyword?
I’m tempted to ask, but I’m not sure I’ll find it helpful, but how would you tell the linker to do stuff like that? I usually just click the run button on my ide and try not to think about it, maybe sometimes using g++ so I’m not really very familiar with explicitly telling the linker and compiler stuff. Are batch files only on windows or is it like you can literally just download the command? They sound pretty cool.

@jonnin I’ve run into that before! Lol yeah it was a tad bit confusing, but I figured it out. Those rules? Vastly simplifies things. Thank you.
calling convention ... stack?
um. uh. yes.
endian ... handle that kind of stuff
how can you even tell what the endianness or however you say it is? I’m sorry I know so little. 😞
Last edited on
highwayman wrote:
@lastchance external statements? Like with that extern keyword?

Yes, sorry, I meant 'extern' in the first place. 'External' is an attribute in Fortran and I got temporarily confused.


highwayman wrote:
how would you tell the linker to do stuff like that?

The only change is that you may have to add additional libraries. It is possible that your IDE might do that automatically based on the names of the source files; otherwise, you will have to consult the documentation to see how to add libraries to the list that the linker uses.


highwayman wrote:
Are batch files only on windows

Yes, but you can do comparable things with a bash shell (or any other shell) on linux.


highwayman wrote:
I usually just click the run button on my ide

Actually, I think students would understand a great deal more of what was going on if they used the command line in Windows (or a shell in linux). They can actually be extremely powerful. I do all my programming from the command line. You don't have to use a batch file - you could simply type the relevant commands in at the command line.

@lastchance:
1) cool I was right lol.
2) 🤦‍♂️ I can’t believe I didn’t see that! I’ve literally done it before! XD. I’ve never really thought about what you would link in files for besides for a #include. Whenever I want to link stuff the ide can’t see for whatever reason I just run everything out of bash or a Makefile( still trying to understand those..)
3) so like make n stuff. Ok.
4) when I first started out I was taught some stuff about the command line and let me tell you...
Don’t ever subject a beginner to such torture I couldn’t understand a thing they said.

But I will say that it would be nice to learn it later on, I’m trying to look at the shell right now, in fact.
Last edited on
calling convention ... stack?
um. uh. yes.

its not important that you understand this. Its just important that you have both sides using the same agreed upon conventions.
Ill try to explain it briefly... you know that when you write a recursive function, it pushes a hidden stack and reinvokes the function again and again until it reaches a stopping point, then pops back, right? (Hopefully you have seen this?). That is the stack I am speaking of, its part of the hardware, really. Turns out you can handle it a few ways... the caller of a function can be responsible for popping it after a function ends, or the function that ended can do it, … but you have to agree. If one side thinks the function did it and the other thinks the caller does it and they both pop the stack, you are in trouble. That is exceedingly overly simplified, but again, you don't have to know this in any depth, you just need to match them which is usually a macro in C/C++ (ever seen __cdecl type words? that's the C calling convention marker).

Its really easy to tell what endian you have :)
unsigned int test = 255;
unsigned char* cp = (unsigned char*) &s;
check which byte of cp has FF in it.
there are some online code snippets you can search for to test, but that is the idea. I think the new words for endian are 'byte order' as in 'network byte order' … those terms may help.

You don't need to apologize for not knowing this stuff. I know it because I had a long, grueling classical computer science degree that spent way, way too much time on this kind of crap and not anywhere near enough time on object oriented design and higher level concepts. And a lifetime of coding reinforced some of it: after you screw up endian a few times, you remember to watch out for it, and after you figure out how compile a multi language program a time or two, you remember to set your calling conventions. The other stuff is kinda on a per language basis and you hit it when you debug, like the fortran and C 2-d transpose problem. You get it all working, run the code, and it explodes and does random nonsense, so you debug, and then a week or so later realize that your array access is backwards and look it up and see that indeed they arrange their memory differently ….

which comes down to a key point I said above: stay in 1 language as much as you possibly can.
Also, batch meaning .bat files is windows. The concept (a bunch of OS commands executed in order) is available everywhere.
Last edited on
its not important that you understand this.
thought so lol. Thanks for the clarification though. Seeing that endian test example was super helpful, I actually get how to do some things now lol.
stay in 1 language as much as you possibly can

🤷‍♂️ I like poking the bear. It’s just fun learning these things which is probably not a good idea on my part but I literally cannot help myself. If I shouldn’t I shall. Terrible philosophy, But I definitely will at least attempt to stay in c++.

Thanks guys! Super helpful.

Edit:
@jonnin sorry when I said terrible philosophy I meant mine not yours sorry for the ambiguity.
Last edited on
I got you.
I also learn some things in trial by fire fashion, just jump in there and try to make it work. Even if you make an unholy mess, you learn some stuff about both what TO do and what NOT TO do and why. Once you have don this a couple of times, you can make up your own mind about the pros and cons.
Topic archived. No new replies allowed.