cola
cola

Reputation: 12466

How can i access the value of a ruby array in C? (editing array.c:rb_ary_initialize from ruby source code)

arr=Array.new(3)
arr[0]=5
arr[1]=3
arr[2]=2

These lines should call this function, https://github.com/ruby/ruby/blob/trunk/array.c#L568 according to this, http://www.ruby-doc.org/core-1.9.3/Array.html

So I have added couple of lines there to display the values of array. But i didn't get the expected result.

else {
    memfill(RARRAY_PTR(ary), len, val);
    ARY_SET_LEN(ary, len);
    int i;
    int result;
    result = 0;
    VALUE *s_arr = RARRAY_PTR(ary);
    for(i = 0; i < len; i++) {
        result = LONG2NUM(s_arr[i]);
        printf("r: %d\n",result);
    }
}

I got the result like this:

arr=Array.new(3)
arr[0]=5
arr[1]=3
arr[2]=2
r: 9
r: 9
r: 9

Why is this result? Why 9?

I have followed these to solve it:

Can anyone please help to display/printf the value of Ruby array in C?

Upvotes: 0

Views: 200

Answers (1)

mu is too short
mu is too short

Reputation: 434745

This doesn't make any sense:

result = LONG2NUM(s_arr[i]);

LONG2NUM is used to convert a C long int to a Ruby VALUE that holds a number; s_arr[i] is already a VALUE so you're effectively doing things like VALUE v = LONG2NUM((VALUE)5). LONG2NUM is defined in ruby.h as a wrapper for this:

#define LONG2NUM_internal(v) (FIXABLE(v) ? LONG2FIX(v) : rb_int2big(v))

and if v fits in a VALUE without converting it to a bignum, then you end up using this:

#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))

So you're basically doing a bunch of bit wrangling on a pointer and wondering why it always says 9; consider yourself lucky (or unlucky) that it doesn't say segmentation fault.

You want to convert a VALUE which holds a number to a C integer. You probably want to use FIX2LONG:

#define FIX2LONG(x) (long)RSHIFT((SIGNED_VALUE)(x),1)

or NUM2LONG:

#define NUM2LONG_internal(x) ((long)(FIXNUM_P(x) ? FIX2LONG(x) : rb_num2long(x)))
#ifdef __GNUC__
#define NUM2LONG(x) \
    __extension__ ({VALUE num2long_x = (x); NUM2LONG_internal(num2long_x);})
#else
static inline long
NUM2LONG(VALUE x)
{
    return NUM2LONG_internal(x);
}
#endif

So something like this:

long result;
for(i = 0; i < len; i++) {
    result = NUM2LONG(s_arr[i]);
    printf("r: %ld\n", result);
}

Note the switch to %ld since we're using longs now and we always turn on all the picky compiler flags that complain about mismatched printf formats and arguments. Of course, this assumes that you are certain that the array contains numbers that will fit in a C long.

Upvotes: 0

Related Questions