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...?
CodePudding user response:
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);
}