4

I created ruby method in C using Ruby API which receive 3 string arguments:

VALUE cache_class = rb_define_class_under(class, CACHE_CLASS_NAME, rb_cObject);

rb_define_method(cache_class, "cache_test_result", cache_test_result, 3);

In test.rb I called method:

Cache.new.cache_test_result("str1", "str2", "str3")

And C cache_test_result function works strange:

VALUE cache_test_result(VALUE str1, VALUE str2, VALUE str3) {
   int rstr1_len = RSTRING_LEN(str1) + 1;
   char buf_str1[rstr1_len];
   strlcpy(buf_str1, RSTRING_PTR(str1), rstr1_len);

   int rstr2_len = RSTRING_LEN(str2) + 1;
   char buf_str2[rstr2_len];
   strlcpy(buf_str2, RSTRING_PTR(str2), rstr2_len);

   int rstr3_len = RSTRING_LEN(str3) + 1;
   char buf_str3[rstr3_len];
   strlcpy(buf_str3, RSTRING_PTR(str3), rstr3_len);

   printf("buf_str1: %s\n", buf_str1);
   printf("buf_str2: %s\n", buf_str2);
   printf("buf_str3: %s\n", buf_str3);
}

output of this function:

buf_str1: 
buf_str2: str1
buf_str3: str2

why args has offset...?

1 Answer 1

3

To quote the documentation:

The first argument of the C function is the self, the rest are the arguments to the method.

Which means you need to adjust the function prototype and add an additional parameter, e.g.:

VALUE cache_test_result(VALUE self, VALUE str1, VALUE str2, VALUE str3) {

And since a C object of type VALUE can be everything (a Ruby string, integer or nil) never use RSTRING_{PTR,LEN} and similar (macro) functions without being sure of its Ruby type. Instead you may use Check_Type, StringValuePtr, or StringValueCStr depending on the use case.

Your example could be rewritten as:

VALUE cache_test_result(VALUE self, VALUE str1, VALUE str2, VALUE str3) {
   // Check if each value is a Ruby string
   // (or can be implicitly converted to one) and
   // return a pointer to its underlying C string.
   // It it also checked if the Ruby string contains NUL.
   // If any check fails an exception is raised.
   const char *buf_str1 = StringValueCStr(str1);
   const char *buf_str2 = StringValueCStr(str2);
   const char *buf_str3 = StringValueCStr(str3);
   // print each underlying C string
   printf("buf_str1: %s\n", buf_str1);
   printf("buf_str2: %s\n", buf_str2);
   printf("buf_str3: %s\n", buf_str3);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.