nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.48k stars 284 forks source link

how to use va_list in node.js #1898

Closed Ash46 closed 5 years ago

Ash46 commented 5 years ago

My c code has a callback as int func(void, int, const char, va_list);

I am trying to use the same function as callback in Node.JS

Platform is Linux.

I have written my callback as

var  valist = struct({
   gp_offset : 'int',
   fp_offset : 'int',
   overflow_arg_area : PVOID,
   reg_save_area : PVOID
});

var valistptr = arrayType(valist, 1);

var callback = ffi.Callback('int',[PVOID,'int','string',valistptr],callback_func);

function callback_func(stream,msgId,format,ap)
{
console.log(ap) // has garbage values.
}

I cannot retrieve the right values from the last argument which is va_list. It has some garbage.

So, what is the right way to use va_list in node.js and is there any equivalent for vprintf(format,args) ?

prettydiff commented 5 years ago

It seems like your question is more around basic JavaScript semantics opposed to anything specific about Node.js. As somebody without a C background I had to look some things up:

term definition citation
va_list a list of function arguments http://www.cplusplus.com/reference/cstdarg/va_list/
vprintf print to stdout using like printf but allows a variable formatter http://www.cplusplus.com/reference/cstdio/vprintf/
printf writes a string to stdout with a bunch of format specifiers http://www.cplusplus.com/reference/cstdio/printf/

A brief introduction to some JavaScript conventions is in order. Please bear with me as I am having some trouble understanding your brief code sample.

First, please understand that in JavaScript functions are just a data type with some features opposed to a special structure. This is referred to as first class citizens in that functions can be used and referenced in any way that a primitive data type can. Functions can be passed into other functions as arguments, can be returned from functions, can return any data type, and be used like any other variable or data type. Better still is that functions can be nested, which is the purest expression of lambda calculus such that nesting creates a mathematical layering of abstractions that minimizes complexity as directly as possible.

Second, JavaScript doesn't have a printf equivalent. It has console.log. The console object is different between the browsers and Node, but the method console.log is close enough to identical. It prints string output to the console. The console.log function is smart enough in all environments that it coerces complex data types directly into a string equivalent for output such that if you provide an array to console.log it will print out the array and the values at each index. If you pass a function reference to a console.log it will print out the function body, such as:

console.log(myfunction); // prints a function body
console.log(myfunction()) // executes the function and prints the function's returned value

If you want something to be formatted in a certain way before its output as a string you need to use some tool or write some code to specify that formatting. This is not typically a major concern, because console.log statements are primarily used for testing or broadcasting execution updates opposed to anything user facing.

Functions in JavaScript have an implicit reference named arguments, example:

var q = function (x, y, z) {
    return arguments;
};
q("a", "b", "c");

When you put that code into a REPL or browser console the output is {0: "a", 1: "b", 2: "c"}. Please keep in mind that JavaScript is loosely typed, so use of arguments is generally a bad idea from a performance perspective. A better idea is to have a fixed number of arguments in a function or the function may not compile in the JIT. If you need to open a function a variable number of arguments without a lose to performance instead specific a single argument that accepts objects or arrays. Also, arguments is an array like structure but is not a true array and does not inherit from the Array prototype. Example:

var myfunction = function (myObject) {
    // something happens in here
};
myfunction({
    first: "z",
    second: "y",
    third: "z"
});

With ES6 there are now several options in JavaScript for data structures, but most of us still just use objects and arrays for data structures. JSON only recognizes objects and arrays. In JavaScript objects are hash maps (key/value pairs) where the key is a always string, but may be expressed as a named reference. Arrays are more similar to tuples in other languages such that they are of variable length and may contain a mix of any data type. Constricting an array to contain a single data type is better for performance in the JIT. Arrays are much faster to iterate over than objects. You can loop through keys of an object, but if the object is large you will pay a performance penalty for doing this directly. To solve for this ES5 provides the convenience method Object.keys(myObject) which returns an array of key names that can be iterated over.

Objects can be accessed variably using a convention called array notation. I am pretty certain C has this. I know Java does. Example: myObject[myVariable]. A developer named Paul Heckel discovered in the late 70s or early 80s that in C hash maps are randomly accessed when using a convention like array notation and its incredibly fast. The performance is variable but is often faster than accessing a specified index of an array and that performance gap widens as the data structure gets larger. He used this concept to create the 6 step Heckel Diff algorithm. I was able to get that 6 step algorithm down to 4 steps in my own application, but it requires some added logic for error correction.

gireeshpunathil commented 5 years ago

closing as answered, feel free to re-open if there is anything unanswered / outstanding