简体   繁体   中英

Passing an “adress” as a function argument - Python 3

I'm trying to use a C file that contains two functions, and one of them is a function that takes as argument the address of a variable (in C denoted by "&" and changes the value of that variable (at least this is what I believe)). Here are the functions (They are kind of complicated to understand)

#define LEN 255
static float u[97],c,cd,cm;
static int i97,j97,ileft;

ranmar1_(ran)
float *ran;
   {
   register float uni, cint;
   register float* listptr;
   register int ivec,i97int,j97int;
   static float rvec[LEN];
   if (ileft < 0)
      {
      i97int = i97;
      j97int = j97;
      cint = c;
      for (ivec = 0; ivec <= LEN; ivec++)
         {
         uni = u[i97int] - u[j97int];
         if (uni < 0) uni++;
         u[i97int--] = uni;
         if (i97int < 0) i97int = 96;
         j97int--;
         if (j97int < 0) j97int = 96;
         cint -= cd;
         if (cint < 0.) cint += cm;
         uni -= cint;
         if ( uni < 0.) uni++;
         rvec[ivec] = uni;
         }
      ileft = LEN;
      c = cint;
      j97 = j97int;
      i97 = i97int;
      }
   *ran = rvec[ileft--];
   }
/*****************************************************************/
rmarin_(ij,kl)
int ij,kl;
   {
   int i,j,k,l,m,ii,jj;
   float s,t;
    printf("%d\n",ij);
    printf("%d\n",kl);
    printf("*******************\n");
   i = ((ij/177) % 177) + 2;
   j = (ij % 177) + 2;
   k = ((kl/169) % 178) + 1;
   l = kl  % 169;
   for (ii = 0; ii <= 96; ii++)
      {
      s = 0;
      t = .5;
      for (jj = 1; jj <= 24; jj++)
         {
         m = (( (i*j) % 179)*k) % 179;
         i = j;
         j = k;
         k = m;
         l = (53*l +1) % 169;
         if (( (l*m) % 64) >= 32) s = s + t;
         t = 0.5 * t;
         }
      u[ii] = s;
      }
   c = 362436./16777216.;
   cd = 7654321./16777216.;
   cm = 16777213./16777216.;
   i97 = 96;
   j97 = 32;
   ileft=(-1);
   }
/*****************************************************************/

An example of the usage in C would be:

int seed1;
int seed2;

rmarin_(seed1,seed2);
float rand;
ranmar1_(&rand);

And so the value of the variable "rand" would be some pseudo-random value between 0 and 1. I'm trying to use these functions in Python but there is a problem. I'm using id(x) as &x because it's the only thing I found to be at least relate. Here is my code:

from ctypes import *

ext = CDLL('./ranmar.so')

seed1 = 11
seed2 = 20
x = 2
ext.rmarin_(seed1,seed2)

ext.ranmar1_(id(x))

print(x)

Notice that I am first using the C file to create a .so file, and then use it in Python3. The problem is that the value of x remains unchanged. How can I make the value of x change to a pseudorandom number between 0 and 1?

Setting aside the strange nature of the C code, id(x) in Python is not an address. It's an identifier that is unique to a given object, but other than that the Python runtime can make it whatever it wants to. It's entirely possible that some implementation of Python could choose IDs from the negative integers (which are clearly not valid addresses).

The standard implementation, CPython, does use an object's address as its ID. But even then, you can't pass that address to a ctypes function that expects a pointer and expect it to work, because the address used to make the ID probably doesn't even point to the value. More likely, it's the address of the Python "wrapper" object. For example, when you write

x = 2

in Python, what happens behind the scenes is somewhat along these lines:

// earlier in the code
struct PyInteger {
    unsigned int reference_count;
    int value;
    // lots of other attributes
};

// ...
const PyInteger* value = PyInteger_from_cache(2);
PySymbolTable* locals = local_symbol_table(stack_frame);
PySymbolTable_set(locals, "x", value);

I mean, that's not the real code, and probably not even all that similar to it - I just came up with this off the top of my head - but at least that should give you an idea that there's a lot more going on at the C level than just assigning a value to a variable. If you were to try to use id(x) as a pointer, given this example code, you'd wind up getting the address of the PyInteger object, not the address of the C int value it holds.

What you should be doing is using ctypes.byref() or ctypes.pointer() to create the pointers which you pass to your C functions. And the objects being pointed to should be instances of eg ctypes.c_int , not Python integers. Python integers are never supposed to change, whereas c_int is allowed to change its value.


Incidentally, if you just want a random number, Python has built-in ways to do that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM