gpt4 book ai didi

c - 为什么静态值在 IRB 内部被破坏?

转载 作者:行者123 更新时间:2023-12-03 10:00:08 25 4
gpt4 key购买 nike

我正在编写一个调用 Linux 的 utsname.h 的 Ruby 方法。
extconf.rb:

#!/usr/bin/env ruby
require 'mkmf'

abort('Not a linux') unless have_const('linux') || RbConfig::CONFIG['arch'].to_s[/linux/]
abort('No utsname.h') unless have_header('sys/utsname.h')

create_makefile 'utsname'
这是 C 代码,(这并不理想,但我仍在遵循不良做法来了解为什么值在 irb 中被破坏):
#include <sys/utsname.h>
#include "ruby.h"

static struct utsname buf ;
static VALUE machine, nodename ;

void init() {
short status = uname(&buf) ;
if (status > -1) {
machine = rb_str_new_cstr(buf.machine) ;
nodename = rb_str_new_cstr(buf.nodename) ;
} else {
machine = rb_str_new_cstr("") ;
nodename = rb_str_new_cstr("") ;
}
}

static VALUE getMachine(VALUE obj) {
return machine ;
}

static VALUE getNodename(VALUE obj) {
return nodename ;
}

int Init_utsname() {
init() ;
rb_define_global_function("machine", getMachine, 0) ;
rb_define_global_function("nodename", getNodename, 0) ;
}
现在在没有 irb 的 ruby​​ 解释器中编译和运行之后:
$ ruby extconf.rb && make && ruby -r ./utsname.so -e "p [machine, nodename, machine, machine, nodename]"
checking for linux... yes
checking for sys/utsname.h... yes
creating Makefile
linking shared-object utsname.so
["x86_64", "archlinux", "x86_64", "x86_64", "archlinux"]
但是当我在 irb 中运行同样的事情时:
$ irb
irb(main):001:0> require_relative File.join(__dir__, 'utsname.so')
=> true

irb(main):002:0> p [machine, nodename, machine, machine, nodename]
["x86_64", "archlinux", "x86_64", "x86_64", "archlinux"]
=> ["x86_64", "archlinux", "x86_64", "x86_64", "archlinux"]

irb(main):003:0> a = ''.match //
=> #<MatchData "">

irb(main):004:0> p [machine, nodename, machine, machine, nodename]
[[], ["irb(main):003:0> "], [], [], ["irb(main):003:0> "]]
=> [[], ["irb(main):003:0> "], [], [], ["irb(main):003:0> "]]
这随机发生有时节点名是一个字符串,有时,它是一个匹配数据,有时,它是别的东西,有时我让整个 Ruby 解释器崩溃(段错误)。
现在,如果我修改我的 C 代码,使机器和节点名成为局部变量,并且可以可靠地工作:
#include <sys/utsname.h>
#include "ruby.h"

static struct utsname buf ;
static short status ;

void init() {
status = uname(&buf) ;
}

static VALUE getMachine(VALUE obj) {
VALUE machine = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.machine) ;
return machine ;
}

static VALUE getNodename(VALUE obj) {
VALUE nodename = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.nodename) ;
return nodename ;
}

int Init_utsname() {
init() ;
rb_define_global_function("machine", getMachine, 0) ;
rb_define_global_function("nodename", getNodename, 0) ;
}
发生什么了?为什么第一个 C 代码有问题?

最佳答案

您可以通过确保 Ruby 保留对您的对象的引用并且不尝试 GC(或压缩)它们来实现此目的。最简单的方法可能是 use rb_global_variable :

Notice: GC should know about global variables which refer to Ruby's objects, but are not exported to the Ruby world. You need to protect them by

void rb_global_variable(VALUE *var)

在您的情况下,它可能如下所示:
void Init_utsname() {
init() ;
rb_global_variable(&machine);
rb_global_variable(&nodename);
rb_define_global_function("machine", getMachine, 0);
rb_define_global_function("nodename", getNodename, 0);
}

关于c - 为什么静态值在 IRB 内部被破坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65297278/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com