I allocate the buffer at startup time and keep it around for all kinds of messages. So there is always a buffer available to send data back and forth. The same buffer can be used for different data structs.
To access the buffer from C you can store the pointer to it in a local variable, e.g.
#define msgInit 0
#define msgMyStruct 1
void *trainBuf = 0L;
int sendMessage(int msgType, void* param){
switch (msgType){
case msgInit:
trainBuf = param;
break;
case msgMyStruct:
//see above
break;
}
So at init time you allocate the buffer on the js side, then send a msgInit to store the pointer (which is an int only) in a local variable. From there on you can use it from both sides:
int msgToJS(float a, float b, float c){
myStructPtr p = (myStructPtr)trainBuf;
p->a = a;
p->b = b;
p->c = c;
//then you notify the JS side:
#ifdef __EMSCRIPTEN__
EM_ASM_({
//whatever you want to do there. The data will be in central.trainBuf and can be extracted the same way you inserted it when sending the message.
#endif //__EMSCRIPTEN__
Regarding your second question:
As said, I keep this buffer alive because I'm sending lots of data back and forth. But of course, you can free the buffer as soon as you have read its contents every time.