The following C function populate a C struct in Visual Works (is working ok):
<C:int ssh_pki_import_pubkey_file (const char * filename, VOID * pkey)>
Now a second function is defined as:
int ssh_userauth_try_publickey (ssh_session session, const char * username, const ssh_key pubkey)
In Smalltalk:
<C:int ssh_userauth_try_publickey (VOID session, const char * username, const VOID pubkey)>
If i call the second function (ssh_userauth_try_publickey) with the populated argument (with no transformation) of the first function (ssh_pki_import_pubkey_file) it fail.
So VOID * pkey has to match const VOID pubkey.
In GemStone/S this is done with #'&ptr' and #'ptr', so #'&ptr' will get the value of the pointer (the CPointer’s value will be passed and updated on return).
Reading DLL & C Connect User’s Guide does not yield result yet.
Short answer
use void** in your first function and void* in your second function
Long answer
In C, void means "nothing" and if you have a return type of void that means you don't return anything.
But void* means pointer to nothing (...that i know about)... basically you get a pointer to something where you don't know what it is. But it's still a pointer, which is not nothing.
If you have a function that produces a value not via return but via parameter, you need to pass a pointer so that the function can set its value. You can do that via void* but that's unintentional. Consider the following wrong C code:
void var;
myFunc(&var);
myFunc would take a void* as parameter in order to fill its value, but a variable of type void is wrong because what would be its value. In correct C you would do it like that:
void* var = NULL;
myFunc(&var);
Here the type of var is clearly a pointer and its value is even initialised. For myFunc there's no real difference here, except that it'll now have a void** as parameter.
So if you modify ssh_pki_import_pubkey_file's declaration to have a void** parameter and change ssh_userauth_try_publickey's declaration to accept a void* parameter, you should be fine.
Trying to interface with a C library that takes a struct with a bunch of pointers to functions it calls at various points.
something like this:
struct callbacks {
int (*foo)(int);
int (*bar)(int);
}
int set_callbacks(callbacks *cbs);
I can make my callbacks:
sub foo-callback(int32 --> int32) {...}
sub bar-callback(int32 --> int32) {...}
It would be cool if this worked:
class Callbacks is repr<CStruct>
{
has &.foo (int32 --> int32);
has &.bar (int32 --> int32);
}
but it doesn't. I'm trying to do something with:
class Callbacks is repr<CStruct>
{
has Pointer $.foo;
has Pointer $.bar;
}
and set those to nativecast(Pointer, &foo-callback) or some such, but I can't
seem to force them in there.
Is there any way to do this beyond writing a little C function that takes all the Perl 6 function pointers and plugging them in the structure in C?
I still can't find an official way to do this, but I figured out a work-around.
Declare a version of sprintf that takes a function pointer of the right type (so it will set up the calling shim correctly), but cheat and have sprintf just give me back the pointer as a number (%lld) I can stuff in the Pointer.
class Callbacks is repr<CStruct>
{
has Pointer $.foo;
has Pointer $.bar;
sub sprintf(Blob, Str, & (int32 --> int32) --> int32) is native {}
submethod BUILD(:&foo, :&bar)
{
my $buf = buf8.allocate(20);
my $len = sprintf($buf, "%lld", &foo);
$!foo := Pointer.new($buf.subbuf(^$len).decode.Int);
$len = sprintf($buf, "%lld", &bar);
$!bar := Pointer.new($buf.subbuf(^$len).decode.Int);
}
}
sub foo-callback(int32 $x --> int32) {...}
sub bar-callback(int32 $x --> int32) {...}
my $callbacks = Callbacks.new(foo => &foo-callback,
bar => &bar-callback);
If you have multiple callbacks with different signatures, just declare a sprintf for each C calling signature you need, e.g.:
sub sprintf-ii(Blob, Str, & (int32 --> int32) --> int32)
is native is symbol('sprintf') {}
sub sprintf-isi(Blob, Str, & (int32, Str --> int32) --> int32)
is native is symbol('sprintf') {}
and call the right sprintf-* for each callback pointer you need.
There is probably an easier way than going back and forth with the pointer to number to string to number to pointer, but this does the trick for now.
i'm a novel developer and i would like to know in yours experience what is the better approach when your building class methods, and if there is not a better approach, how balance your decisions with respect to:
Pass as arguments a big object that contains most of the variables needed for the method.
Pass the more atomic individuals variables possibles, with the consequences of generate methods with big signatures.
What is better for a code that is going to evolve? and what do you think is a reasonable number of arguments?
I would argue strongly in favor of passing around an object, if the commonality in the sets pf arguments allows it.
Why?
Because X% of effort goes to maintain existing code and it's a LOT harder to add new parameters - especially in methods that chain-call each other and pass those new parameters - than to add a property to an object.
Please note that this doesn't have to be a CLASS per se, in a sense of having methods. Merely a storage container (either a heterogeneous map/dictionary, or for type safety, a struct in C-type langages that support it).
Example (I'll use pseudocode, feel free which language(s) it's based on):
First, let's see old and new code using argument lists
Old code:
function f1(arg1, arg2, arg3, arg4, arg5) {
res = f2(arg1, arg2, arg3, arg4);
}
function f2(arg1, arg2, arg3, arg4) {
res = f3(arg1, arg2, arg4);
}
function f3(arg1, arg2, arg4) {
res = f4(arg1, arg4);
}
function f4(arg1, arg4) {
return arg1 + arg4;
}
New code (need to add arg6 in f4()):
function f1(arg1, arg2, arg3, arg4, arg5, arg6) { // changed line
res = f2(arg1, arg2, arg3, arg4, arg6); // changed line
}
function f2(arg1, arg2, arg3, arg4, arg6) { // changed line
res = f3(arg1, arg2, arg4, arg6); // changed line
}
function f3(arg1, arg2, arg4, arg6) { // changed line
res = f4(arg1, arg4, arg6); // changed line
}
function f4(arg1, arg4, arg6) { // changed line
return arg1 + arg4 + arg6; // changed line
}
As you can see, for 4-level nested calls, we changed ALL 4 functions, at the volume of at least 2 lines per function. YIKES. So for 10-level nested calls, adding 1 parameter changes all TEN functions and 20 lines.
Now, an example of the same change, except the arg list is now an object (or, for dynamic languages, a heterogeneous map would do :)
class args_class {
public:
int arg1, arg2, arg3, arg4, arg5;
}
}
args_class arg_object;
function f1(arg_object) {
res = f2(arg_object);
}
function f2(arg_object) {
res = f3(arg_object);
}
function f3(arg_object) {
res = f4(arg_object);
}
function f4(arg_object) {
return arg_object.arg1 + arg_object.arg4;
}
And what do we change to add arg6?
class args_class {
public:
int arg1, arg2, arg3, arg4, arg5, arg6; // line changed
}
}
// f1..f3 are unchanged
function f4(arg_object) {
return arg_object.arg1 + arg_object.arg4 + arg_object.arg6; // line changed
}
That's it. For 4-level nested methods, or for 10-level nested methods, you ONLY change 2 lines both.
Which one is less work to maintain?
I think it all depends on the context of the function parameters themselves. If you're relying on elements of some thing, then I'd pass a reference of that some thing as a parameter (whether it's a reference/pointer to an interface of that object or a reference/pointer to the object definition itself is an implementation detail).
If the parameter isn't derived directly from an object and there are a small number of parameters (five or less maybe? up to you really), then I'd pass atomic arguments.
If there are potentially a large number of arguments, then I'd create some sort of an init struct as a parameter, where the calling code instantiates and fills the struct and then passes a reference to it as an argument.
Suppose I write the following code:
public ref class Data
{
public:
Data()
{
}
Int32 Age;
Int32 year;
};
public void Test()
{
int age = 30;
Int32 year = 2010;
int* pAge = &age;
int* pYear = &year;
Data^ data = gcnew Data();
int* pDataYear = &data->Year; // pData is interior pointer and the compiler will throw error
}
If you compile the program, the compiler will throw error:
error C2440: 'initializing' : cannot convert from 'cli::interior_ptr' to 'int *'
So I learned the "&data->Year" is a type of interior pointer.
UPDATES: I tried to use "&(data->Year)", same error.
But how about pAge and pYear?
Are they native pointers, interior pointers or pinned pointers??
If I want to use them in the following native function:
void ChangeNumber(int* pNum);
Will it be safe to pass either pAge or pYear?
They (pAge and pYear) are native pointers, and passing them to a native function is safe. Stack variables (locals with automatic storage lifetime) are not subject to being rearranged by the garbage collector, so pinning is not necessary.
Copying managed data to the stack, then passing it to native functions, solves the gc-moving-managed-data-around problem in many cases (of course, don't use it in conjunction with callbacks that expect the original variable to be updated before your wrapper has a chance to copy the value back).
To get a native pointer to managed data, you have to use a pinning pointer. This can be slower than the method of copying the value to the stack, so use it for large values or when you really need the function to operate directly on the same variable (e.g. the variable is used in callbacks or multi-threading).
Something like:
pin_ptr<int> p = &mgd_obj.field;
See also the MSDN documentation
The unmanaged function(pure c++, if that matters):
void fooC(float& result);
I define the wrapper as (managed wrapper, c++\cli):
void foo(float% result) //managed interface, need to pass result back to caller
{
fooC(???);//how to call unmanaged function?
}
how to pass reference parameter in the wrapper?
You can't convert a tracking reference to an unmanaged reference or pointer. The garbage collector would cause havoc when the passed float is a field in an object. You'll need to use a temporary:
void foo(float% result) {
float temp;
fooC(temp);
result = temp;
}