- 浏览: 427808 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
lkun__blog:
网页打不开啊
博客搬家到http://cuiz.me -
bglmmz:
楼主怎么解决的?我用python调用ice服务,也出现此问题, ...
syscall exception: 存储空间不足,无法处理此命令 -
luliangy:
哥,你什么配置,我10W个请求10秒左右就搞定了,毫无压力,R ...
Nginx和Apache简单的并发压力测试 -
liuxuejin:
这!看的我都···········。我看代码而已。怎么
EPOLL及消息队列实现SMTP 之 青楼的故事 -
zires:
night_stalker 写道unicorn 也很好维护啊, ...
Unicorn和Passenger性能测试对比
上一篇文章我们找到了如何调试Ruby的入口,只要走进去,我们就有可能揭开Ruby的奥秘.但如果我说我要从每个分支都走一遍,每个函数都解读一遍,这可是impossible mission,我肯定没那么强大的理解力,要知道,在没有充分理解一个Ruby对像的实现之前就去阅读它的源码,那大部分的理解都是靠猜测,成功的几率不大,看你的运气以及能得到多少资料.
用过Ruby的人都该知道,Ruby里面没有数据类型的概念:Type是模糊的,但Value是绝对的;123可以是Fixnum,也可以马上变成Bignum,但123就是123,它的值是不变的.
所以当我们阅读R
uby源码的时候,我们看到满眼的声名为VALUE类型的变量,这其实就是Ruby的对象,它是一个指针,指向一块内存,内存里面的数据是值,是结构体,如果你认为它是Fixnum类型(T_FIXNUM),那么你就用FIXNUM_P这个宏去检测一下,如果返回Qtrue,那么恭喜,你的运气很好,一次就碰对了,同时,你马上可以用FIX2INT() or FIX2LONG()这两个宏把它的值在gdb里面打印出来(print或者p);如果返回的不是Qtrue,那么很可惜,你必须继续尝试,在R
uby中处理未知数据类型时,通常用如下代码来完成检测过程,而且随着判断类型的增多,代码会更加冗余:
switch (TYPE(obj)) {
case T_FIXNUM:
/* process Fixnum */
break;
case T_STRING:
/* process String */
break;
case T_ARRAY:
/* process Array */
break;
default:
/* raise exception */
rb_raise(rb_eTypeError, "not valid value");
break;
}
上面这个例子说明了些什么呢?可以说明能量守恒的定理么?我觉得是的,动态语言灵活了,你可以不需要指定类型的去使用,写起代码来一大堆的黑魔法让人看得眼花缭乱.但实际上它的实现过程中却为了作了判断类型的操作,同时由于类型的不确定性,我们还不得不为不管多精简的代码花费这些时间,这就是代价,有得亦有失,这不就是能量守恒么?
由于类型的不确定,由于无论是字符串还是数字还是指针,看起来都是VALUE类型,让我们难以猜测,所以我们这次Ruby调试之旅会很艰苦,因为当我们进入一个断点,watch一个变量的时候,我们将无从下手,我们不知道是该以什么类型去print这个VALUE指针.假如我们得到了一个VALUE变量,我们想拿到它的值,比如String的字符,Fixnum的数值,或者Hash的Key,我们都必须去用(类型_P)这个宏去探测,如果你有阅读过并且读懂了源码,那么恭喜你,你可以根据上下文进行猜测,这样命中的几率大的很多.但在没有找到更好的调试方法之前,让我们多干点好事吧(积德).
ps:rb_type这个函数可以帮我们做一些简单判断:
static inline int
rb_type(VALUE obj)
{
if (IMMEDIATE_P(obj)) {
if (FIXNUM_P(obj)) return T_FIXNUM;
if (obj == Qtrue) return T_TRUE;
if (SYMBOL_P(obj)) return T_SYMBOL;
if (obj == Qundef) return T_UNDEF;
}
else if (!RTEST(obj)) {
if (obj == Qnil) return T_NIL;
if (obj == Qfalse) return T_FALSE;
}
return BUILTIN_TYPE(obj);
}
我不该说这么多调试的痛苦,但这些废话还是有点价值的,比如就引出的Ruby在C中的数据结构.如果专门说这个数据结构,我想这一篇肯定说不完了,但我这一篇是想介绍Ruby在main方法中几个初始化过程的,所以我简单的说一下R
uby的几个重要的数据结构.
Ruby的数据都是以VALUE类型存放的,VALUE的定义如下:
typedef unsigned long VALUE;
VALUE类型如此简单,这就是一个指针么.也就是说,在Ruby中,数据都是以指针方式来访问的(除了Fixnum),当我访问的时候,我通过类型转换将这个指针变成我期望的类型,比如我拿到了一个指针h并且我知道它的类型是Hash,那么h所指向的那片内存区域肯定存放了一个Hash对象,我现在要操作这个对象该怎么办?通过如下的宏来实现:
RHASH(h)->hash_method
#define RHASH(obj) (R_CAST(RHash)(obj))
R_CAST,顾名思义,将obj转换为RHash类型,它的实现如下:
#define R_CAST(st) (struct st*)
呵呵,很容易就能看懂吧,Ruby的实现中使用了大量的宏来简化操作,同时又能给出平易近人的命名方式,这使得我们阅读的时候顺畅了不少,感谢Core Team,不过也别忘了上一篇我为什么要强调编译Ruby时的那几个参数了,如果不加上,我们是无法在gdb的时候去通过
GDB 写道
info macro RHASH
来看到RHASH的实现的.
上面是以一个Hash对象的操作为例,讲解R uby对象的存在方式(VALUE指针),以及习惯的操作方法(R_CAST转换).不过刚才也提到过Fixnum不是指针,为啥?如果一个VALUE的类型你能确定是Fixnum的话,就不需要去通过*取值了,我们可以直接拿到Fixnum的指,因为VALUE这个unsign long已经足够大了,它的长度足够存储一个Fixnum,所以Fixnum是以值而不是指针的形式存在的.
这也就说道Ruby中哪些类型是传值的,哪些类型是传址的.如果死记硬背那些教条,我估计肯定没有自己去发现Ruby的底层实现给你的印象更深刻.
下面这几个类型也很重要,尤其是True和False.
RUBY_Qfalse = 0,
RUBY_Qtrue = 2,
RUBY_Qnil = 4,
RUBY_Qundef = 6,
上面是这几个类型的值,千万不要小看这几个值阿,他们可不是随便写写的,他们的用处可巧妙了,比如给你看一个宏的实现,
#define RTEST(v) (((VALUE)(v) & ~Qnil) != 0)
这个宏是用作判断一个VALUE对象是否为True或者为False和Nil的,这个判断就用到了上面的几个值的特点,为了让Ansi C的
if表达式在False和Nil的时候都走失败的分支,而只有True的时候走成功的分支.至于怎么实现,请用位运算计算一下,看看是不是取值设计的巧妙.
#define Qfalse ((VALUE)RUBY_Qfalse)
#define Qtrue ((VALUE)RUBY_Qtrue)
#define Qnil ((VALUE)RUBY_Qnil)
#define Qundef ((VALUE)RUBY_Qundef) /* undefined value for placeholder */
Ruby的数据类型远远没有讲清楚呢,那些各种Ruby层对象所对应的C层的结构体,那些Hash存储策略的设计及Hash算法的选择,RString结构变长存储的设计思路和成员aux的作用等,这些我几乎都没有提到过呢.但这不会影响我们继续探索下去,相信我,知道上面那些就足够我们迈步向前了,起码我自己还什么都不懂呢,所以你们别担心.......
好晚了,写着写着,不知不觉就半夜了,明天还要早起,我发现我离原定要写的内容还有好大一截,反倒是想给大家普及的一些基本知识说了好多,剩下本来要讲Ruby解释器初始化的部分,都准备好了一些代码,但我困了,擦,再不睡觉明天要误事了.我就放到下一章吧.好像一口气读完R
uby的实现,但那样不会理解它的精髓,我们要取其精华去其糟粕,慢慢来啊.
============================================================
下面是准备好了的第三篇的部分东西,先放到这里,大家预习下.
/**********************************************************************
main.c -
$Author: akr $
created at: Fri Aug 19 13:19:58 JST 1994
Copyright (C) 1993-2007 Yukihiro Matsumoto
**********************************************************************/
#undef RUBY_EXPORT
#include "ruby.h"
#include "debug.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
RUBY_GLOBAL_SETUP
int
main(int argc, char **argv)
{
#ifdef RUBY_DEBUG_ENV
ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
setlocale(LC_CTYPE, "");
#endif
ruby_sysinit(&argc, &argv);
{
RUBY_INIT_STACK;
ruby_init();
return ruby_run_node(ruby_options(argc, argv));
}
}
#define CALL(n) {void Init_##n(void); Init_##n();}
void
rb_call_inits(void)
{
CALL(RandomSeed);
CALL(sym);
CALL(var_tables);
CALL(Object);
CALL(top_self);
CALL(Encoding);
CALL(Comparable);
CALL(Enumerable);
CALL(String);
/*..........*/
}
README.EXT 写道
4. Example - Creating dbm extension
......
(3) write C code.
......
Ruby will execute the initializing function named ``Init_LIBRARY'' in
the library. For example, ``Init_dbm()'' will be executed when loading
the library.
Here's the example of an initializing function.
--
void
Init_dbm(void)
{
省略
}
--
......
(3) write C code.
......
Ruby will execute the initializing function named ``Init_LIBRARY'' in
the library. For example, ``Init_dbm()'' will be executed when loading
the library.
Here's the example of an initializing function.
--
void
Init_dbm(void)
{
省略
}
--
评论
1 楼
night_stalker
2010-08-23
就算是静态类型语言,往往也有运行期类型检查 ……
VALUE 是一种 tagged pointer,tagged pointer 的应用广泛的 …… 连 C 语言的指针都可以看作一种 tagged pointer,其 0(NULL) 值就不是指针量。
Ruby 里面调用方法之前只对是否为直接量作检查(IMMEDIATE_P;见 ruby.h 里面 rb_class_of 的定义),这个基本不算速度的瓶颈 ……
VALUE 是一种 tagged pointer,tagged pointer 的应用广泛的 …… 连 C 语言的指针都可以看作一种 tagged pointer,其 0(NULL) 值就不是指针量。
Ruby 里面调用方法之前只对是否为直接量作检查(IMMEDIATE_P;见 ruby.h 里面 rb_class_of 的定义),这个基本不算速度的瓶颈 ……
发表评论
-
N度空间关系图
2011-05-11 17:22 1595计算机 ... -
Rails3和Rack依赖关系图
2011-05-11 17:17 0找到一个好的画图工具不容易啊,试试这个 -
Unicorn和Passenger性能测试对比
2011-05-03 13:04 4351测试工具:ab 测试 ... -
libsmtp--库的一个bug
2011-02-18 17:09 1878http://libsmtp.sourceforge.net/ ... -
从main.c开始走进Ruby-异常
2010-08-26 18:21 1169这一阵子真没时间,9月上旬更没时间,头大. 前天写面试题目的 ... -
从main.c开始走进Ruby-登上调试Ruby之旅
2010-08-18 12:11 1287我想更深入的了解Ruby内 ... -
日积月累-分享我的工具库
2010-08-04 11:53 1249批量替换 指定目录及其子目录中所有文件内的字符串 ... -
关键字和预定义变量:__END__和DATA的问题
2010-05-13 10:07 1323两个文件,a.rb和b.rb 当a.r ... -
[J]Ruby自编译安装
2010-02-24 11:37 1345#直接Copy并粘贴到控制台 #安装Ruby1.9.1- ... -
libvirt和ruby-libvirt在Macos系统上安装失败解决方法
2010-01-22 17:31 1179附件中是补丁及安装脚本, 安装前先看下install那个脚本 ... -
【GUI】LoadRunner的Controller定时执行
2010-01-19 14:38 3721玩玩的,很好玩不是么,工作就是要好玩,否则还工作个屁啊。 ... -
将QC的COM接口开放成Rest服务[续]
2010-01-14 11:53 1535利用QC的开放架构平台的COM组建, 给HP的QC写一个Met ... -
Ruby的ActiveRecord1.9个小时能够插入1000万mysql数据
2009-12-29 15:38 926rtrtrt -
TextMate中Command+R无法执行的变通解决方法
2009-12-28 12:08 2757如果你在升级了雪豹并且设定为64位启动模式后, TM无法通过C ... -
批量更改主机密码
2009-12-22 17:00 798require "rubygems" r ... -
将QC的COM接口开放成Rest服务
2009-11-16 17:05 2418以Ruby代码为例, QC平台的SDK以COM组件的形式对 ... -
虚拟机!
2009-11-12 16:25 839ruby-libvirt ============ Ruby ... -
Swig编译C/C++代码给Ruby [on Mac]
2009-10-12 15:01 2129charlesdemacbook-pro:swig Cui$ ... -
让一个类include一个模块的几种方法
2009-09-22 10:59 824module Test module ClassMeth ... -
ruby中当前系统分隔符
2009-09-08 15:28 803$/
相关推荐
| | |-- main.c | | |-- Makefile | | |-- nand.c | | |-- s3c24xx.h | | |-- serial.c | | `-- serial.h | |-- hello | | `-- hello.c | |-- i2c | | |-- head.S | | |-- i2c.c | | |-- i2c.h | | |-- i2c.lds | | ...
2004-07-16 13:16 24036 2415 BusinessSkinForm\Ampix\main.bmp 2004-07-09 21:54 3422 91 BusinessSkinForm\Ampix\mask.bmp 2004-07-16 13:17 8912 1183 BusinessSkinForm\Ampix\menuitems.bmp 2004-07-16 13:17 ...
编译原理 C语言编译器(包括词法/语法/语义分析器等) 项目结构如下 -source --lexAnalysis 词法分析器(原创) ---analyse.c 词法分析器 ---text.c 测试用例(被分析的C代码) --lexSynAnalysis 语法分析器(转存...
main.c Makefile.multi-target.template print_int_array.c.noindent .vim/c-support/doc: ChangeLog c-hotkeys.pdf c-hotkeys.tex .vim/c-support/rc: customization.ctags customization.gvimrc customization....
通过这个“Ruby学习指南”,你可以从基础到高级,全面掌握Ruby编程,包括类的设计、面向对象编程的精髓、元编程的技巧,以及如何利用Ruby的Gem生态进行高效开发。通过实践其中的示例和项目,你将能够深入理解并熟练...
The main directory where all μC/OS-II files are located. \SOFTWARE\uCOS-II\EX1_x86L This directory contains the source code for EXAMPLE #1 (see section 1.07, Example #1) which is intended to run ...
Ruby是一种面向对象的、动态类型的编程语言,以其简洁、优雅的语法和强大的元编程能力而闻名。在这个"Ruby-一个Ruby的例子"中,我们将探讨Ruby的基础知识,以及如何通过具体的代码示例来理解其核心特性。 首先,...
gcc common.c main.c menu.c guide.c game.c -o RUN -lSDL2main -lSDL2 -lSDL2_image -lSDL2_ttf 2. 使用Clion编译 请注意文件夹中的```CMakeLists.txt``` 在编译时,请点开**编辑配置**窗口,将**工作目录改为本...
用法Ruby用法示例: $ lsGemfile Gemfile.lock$ heroku create --buildpack heroku/ruby$ git push heroku main...-----> Heroku receiving push-----> Fetching custom buildpack-----> Ruby app detected...
c语言程序,调用cmd运行当前目录下名为main.pyw或main.py的文件
- C程序从main()函数开始执行,直到main()函数结束。 4. C语言语句: - 选项D(p&&=q)不正确,因为C语言中没有逻辑与赋值运算符。 5. C语言关键字: - 选项A中,'define', 'getc', 'include'不是C语言的关键字...
哈夫曼编码实现_c语言 (最小堆) 求WPL -----递归求解
Ruby是一种强大的动态编程语言,常用于Web开发、脚本编写以及构建命令行工具。在创建命令行接口(CLI)时,通常需要编写大量的代码来处理命令解析、参数验证和业务逻辑。为了简化这一过程,开发者们创造了各种工具,...
这是因为`m1`中的`main`函数实际上从`0x5589`地址开始执行,这是通常的栈帧布局的一部分,其中`%ebp`寄存器的初始值。 理解这些概念对于编写和调试多文件C程序至关重要,特别是在处理全局变量和函数时,以及在模块...
- `main()`函数是C程序的入口点,程序从这里开始执行。 - C语言标准没有强制规定`main()`函数的名称必须为`main`,但实际上几乎所有C程序都使用这个名字。 - **算法的概念**: - **算法**定义了一组解决问题的...
改进的CC方法 - \C-C Method Improved\Main_CC_Method_Improved.m (5)求关联维(correlation dimension) GP算法 - \CorrelationDimension_GP\Main_CorrelationDimension_GP.m (6)求K熵(Kolmogorov Entropy) GP算法 ...
例如,从1.0到1.8的升级可能增加了对更多压缩格式的支持,提高了处理速度,或者解决了之前版本中存在的一些兼容性和稳定性问题。 在Java编程中,`commons-compress.jar` 可以通过以下步骤使用: 1. **添加依赖**:...
Logstash 是一个强大的数据收集、处理和转发工具,广泛用于日志管理和实时数据分析。这个压缩包 "logstash-codec-json-lines-main.tar.gz" 提供的是 Logstash 的一个插件,名为 "json_lines" 编解码器。这个编解码器...
1. /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start’:(.text+0x18): undefined reference to `main’collect2: ld 返回 1Reason: no main function in source file2....
用于Ruby的Heroku Buildpack 这是用于Ruby,Rack和Rails应用程序的 。 它使用进行依赖管理。 该buildpack需要64位Linux。 用法 Ruby 用法示例: $ ls Gemfile Gemfile.lock $ heroku create --buildpack heroku/...