赞 | 0 |
VIP | 2 |
好人卡 | 27 |
积分 | 1 |
经验 | 26327 |
最后登录 | 2019-10-13 |
在线时间 | 953 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 110
- 在线时间
- 953 小时
- 注册时间
- 2007-4-25
- 帖子
- 805
|
也要考虑数据结构对齐的问题。
- typedef struct cstruct_s {
- int i;
- short s;
- } cstruct;
复制代码 这样的一个结构体,在 ILP32 数据模型下,MSVC /Zp8 编译后的 sizeof (cstruct) 其实是 8。而 Ruby 的 String#pack 包装后的缓冲区却是:- p [0, 0].pack("is") # => "x00x00x00x00x00x00"
复制代码 少了两个字节。如果这时候本地代码尝试访问 cstruct#s,就可能发生 segfault。MSVC 可以指定 /Zp2,即是用 2 个字节的界限来对齐内存,那样话的 sizeof (cstruct) 就可以是 6;GCC 也可以通过 __attribute__ ((aligned (x))) 来指定前面的结构体和联合体的对齐界限。
当然,Windows API 大多数情况下都是在和 32 位双字数据打交道,所以大部分结构都是 4 字节界限对齐的。
显而易见的, 它是一个结构体, 里面的成员变量都是 long 类型的, 于是, 我们需要先创建一个这个结构体的实例:
RGSS2 代码:
lpRect = [0, 0, 0, 0].pack("llll")
如果涉及到的数据类型能大小是确定性的,这种简单的数据的结构就可以直接用字符串表示了:- lpRect = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
复制代码 或是:这避免了 String#pack 的开销。32 位 Windows 采用的是 ILP32 数据模型,而 64 位 Windows 是 IL32P64(或者叫 LLP64),所以 long 类型在 Windows 下基本等同于 int 都是 32 位。只有在使用 LP64/ILP64 模型的系统下(比如 64 位 Linux),long 才是 64 位。
苏小脉于2011-5-15 01:57补充以下内容:不过C的结构体似乎很简洁,能够pack出一个Ruby的结构体么?
理论上是可以的,只要你对特定 Ruby 实现的内部结构有足够的了解,就可以将所有需要的成员都集装到一个数组里,一并包装。这里之所以简洁完全是为了演示目的,教程一开始不需要太复杂的例子——C 结构当然也是可以很复杂的。
Ruby 本身不就是有一个 Struct 类么? 用来处理结构体??
Struct 类定义的是类的模版,可以想成是 Class 实例的工厂,和 C 结构体没有必然的关系。
比如有一个函数用了Ruby写的,要用其他语言结构Ruby的结构体似乎很难
写 Ruby 扩展就可以了。Ruby 提供了不少 C API 用于扩展 Ruby 语言。如果对细节有兴趣,可以参考 Dave Thomas 在《Programming Ruby》中给出的扩展教程。
'P'与'L'一样只限于32位API,在64位中,可能会发生指针截断。
'P' 的话,如果是 32 位的 Ruby build,那确实。64 位的 build,本地指针应该就是按照 64 位来处理的了。
至于 'L',Windows 的本地 long 型永远都是 32 位,只是由于 Ruby 的 Fixnum 用了一位来表示直接值,所以 Fixnum 只能表示 2^31 个数。String#unpack 的时候会调用 num2i32(x),如果 x 超过了 Fixnum 所能表示的长度就会转换为 Bignum 返回给调用者:
- static unsigned long
- num2i32(x)
- VALUE x;
- {
- x = rb_to_int(x); /* is nil OK? (should not) */
- if (FIXNUM_P(x)) return FIX2LONG(x);
- if (TYPE(x) == T_BIGNUM) {
- return rb_big2ulong_pack(x);
- }
- rb_raise(rb_eTypeError, "can't convert %s to `integer'", rb_obj_classname(x));
- return 0; /* not reached */
- }
复制代码 如果要刻意使用 64 位整数,可以:- p [ 2 ** 64 - 1, 2 ** 63 - 1 ].pack('Qq')
复制代码 这个就对对应 long long 型,只是它仅仅存在于 C99 中,不过大部分遵从 C89 的编译器都“部分支持”C99,其中泰半都有对 long long 的支持。
要在其他语言调用ruby的结构和方法必须通过rb虚拟机提供的接口。
(RM 嵌入的)MRI(Ruby 1.8 实现)没有虚拟机,只有 AST Walker。不过本地扩展的接口大致还是和其它版本一致的。
|
|