Why I can not store the address of one variable in “Prolog+C”?
-
21-12-2019 - |
Question
So basically I want to call some C code from Prolog, and here is the code:
Prolog:
:-foreign(fun1(+integer,-integer)).
:-foreign(fun2(+integer,-integer)).
% p = b;
testfuna(Var, Val) :- fun1(Val, Var).
% p = &b;
testfunb(Var, Val) :- fun2(Val, Var).
main :-
A is 1,
testfuna(A, P),
write(P),
testfunb(A, P),
write(P),
% print out
write(A), nl.
C:
#include <gprolog.h>
#include <string.h>
PlBool fun1(int ptr, int* res){
*res = ptr;
printf("%d\n", *res);
if(res==NULL){
return PL_FALSE;
}else{
return PL_TRUE;
}
}
PlBool fun2(int val, int* res){
*res = &val;
printf("%p\n", *res);
if(res==NULL){
return PL_FALSE;
}else{
return PL_TRUE;
}
}
I use this to compile into binary format:
gplc -o sample sample.c sample.pl
The problem is that, after I run this code, the output is :
1 <--- right
1 <--- match, right!
0xbff2160c <-- it is on the stack
-911860 <--- why?
I don't understand why the fourth output is a new memory address, to my understanding, it should also be 0xbff2160c,
am I wrong? Could anyone give me some help?
Solution
There is a difference.
In your function fun2
, you get an integer on the stack, &val
is the address of that integer.
PlBool fun1(int ptr, int* res){
*res = ptr; /* ptr is what you got from prolog */
...
}
PlBool fun2(int val, int* res){
*res = &val; /* val is a copy on the stack here, */
/* you don't use at all what you got from prolog, only the address */
/* of a local copy in the stack */
...
}
Also, ( I don't know any prolog, so I'm not sure what you do in that part ) if you are trying to pass pointers as int
, it won't work.
Generally, the size of pointers, and size of ints can be different. Using int
to store a pointer
is not going to work, e.g. on 64bit intels, usually int
is a 32 bit integer, and a pointer is a 64 bit unsigned integer, that won't fit into 32 bits.
OTHER TIPS
Just a guess, but is it the limit of the size of the integer being passed into prolog ?
I don't know gnu prolog, but in swi prolog there is a special call PL_get_pointer and PL_put_pointer specifically for handling addresses.. PL_get_integer and PL_put_integer won't work. Have a look for the equivalent in gnu.. it's possible the address is being mangled.
Edit: it's possible you might just have to change it from an int to a long, or double.. something like that.