GObject对象系统(2) 背景



GObject, and its lower-level type system, GType, are used by GTK+ and most GNOME libraries to provide:

  • object-oriented C-based APIs and

  • automatic transparent API bindings to other compiled or interpreted languages.

GObject, 以及它底层的GType,被GTK+和大多数GNOME库用于提供:
* 基于C语言的面向对象的API;
* 对其他编译型或解释型编程语言的API自动转换和绑定。
 
A lot of programmers are used to working with compiled-only or dynamically interpreted-only languages and do not understand the challenges associated with cross-language interoperability. This introduction tries to provide an insight into these challenges and briefly describes the solution chosen by GLib.
很多程序员只使用编译型或动态解释型语言,他们并不了解跨语言互操作所要面临的挑战。本文将为这些挑战提供一个内部视角并短暂的说明GLib所采用的解决方案。
 
The following chapters go into greater detail into how GType and GObject work and how you can use them as a C programmer. It is useful to keep in mind that allowing access to C objects from other interpreted languages was one of the major design goals: this can often explain the sometimes rather convoluted APIs and features present in this library.
接下来的章节中我们将介绍GType和GObject的工作原理以及C语言开发者如何使用它们。请记住让其他解释型编程语言访问C语言实现的对象是GObject的主要设计目标之一,因此在GLib库中有时会出现一些比较繁琐的API和特性,这都是为了方便地进行跨语言绑定。
 
 

Data types and programming

数据类型和编程
 
One could say that a programming language is merely a way to create data types and manipulate them. Most languages provide a number of language-native types and a few primitives to create more complex types based on these primitive types.
你可以认为所谓编程语言只不过是提供了一种创建数据类型以及操作这些数据类型的方式。大多数编程语言提供了一系列原生的基础数据类型,以及在这些基础数据类型上创建更复杂的类型的方法。
 
In C, the language provides types such as  charlongpointer. During compilation of C code, the compiler maps these language types to the compiler's target architecture machine types. If you are using a C interpreter (assuming one exists), the interpreter (the program which interprets the source code and executes it) maps the language types to the machine types of the target machine at runtime, during the program execution (or just before execution if it uses a Just In Time compiler engine).
C语言提供了char,long,指针等基础的数据类型,在C语言编译时,编译器将这些类型转换为目标架构的机器类型。如果存在一个C语言解释器,解释器将在解释执行C语言代码时将C语言数据类型转换为机器类型(如果你使用的是JIT解释器,那转换过程在解释执行前进行)。
 
Perl and Python are interpreted languages which do not really provide type definitions similar to those used by C. Perl and Python programmers manipulate variables and the type of the variables is decided only upon the first assignment or upon the first use which forces a type on the variable. The interpreter also often provides a lot of automatic conversions from one type to the other. For example, in Perl, a variable which holds an integer can be automatically converted to a string given the required context:
Perl和Python的解释型语言并没有像C语言一样提供了类型定义语法。Perl和Python的程序员管理变量,而变量的类型有第一次赋值或第一次使用时决定。解释器同时提供了从一个类型到另一个类型的自动转换方法。例如,Perl中一个存储整数的变量可以自动转换为字符串类型:
my $tmp = 10;
print "this is an integer converted to a string:" . $tmp . "\n";

 

Of course, it is also often possible to explicitly specify conversions when the default conversions provided by the language are not intuitive.
当然,当语言提供的默认转换方法不符合需求时,允许显式地使用自定义的类型转换方法。
 
 

Exporting a C API

导出C API
 
C APIs are defined by a set of functions and global variables which are usually exported from a binary. C functions have an arbitrary number of arguments and one return value. Each function is thus uniquely identified by the function name and the set of C types which describe the function arguments and return value. The global variables exported by the API are similarly identified by their name and their type.
C API是一系列从二进制文件中导出的函数和全局变量。C函数有任意数量的参数和一个返回值,每个函数由其函数名与参数和返回值的类型唯一标识。全局变量由变量名和类型唯一标识。
 
A C API is thus merely defined by a set of names to which a set of types are associated. If you know the function calling convention and the mapping of the C types to the machine types used by the platform you are on, you can resolve the name of each function to find where the code associated to this function is located in memory, and then construct a valid argument list for the function. Finally, all you have to do is trigger a call to the target C function with the argument list.
一个C的API仅仅由一个与类型相关的名称定义,如果你知道C函数的调用规则以及C类型到目标机器类型的转换规则,你可以通过函数的名字解析出该函数的代码在内存中的位置,然后构造一个有效的函数参数列表,最后你就可以使用该函数参数列表发起一个对目标函数的调用。
 
For the sake of discussion, here is a sample C function and the associated 32 bit x86 assembly code generated by GCC on a Linux computer:
为了便于讨论,这里有一个C函数以及在Linux计算机上由GCC产生的32位X86汇编代码:
static void
function_foo (int foo)
{
}

int
main (int   argc,
      char *argv[])
{
    function_foo (10);

    return 0;
}

push   $0xa
call   0x80482f4 <function_foo>

 


The assembly code shown above is pretty straightforward: the first instruction pushes the hexadecimal value 0xa (decimal value 10) as a 32-bit integer on the stack and calls  function_foo. As you can see, C function calls are implemented by GCC as native function calls (this is probably the fastest implementation possible).
上述汇编代码所实现的功能很直观:第一行将16进制数字0xa作为一个32位整数压栈,然后调用函数function_foo。正如你所看到的,GCC把C语言函数调用实现为机器原生的函数调用(这也许是最快的实现了)。
 

Now, let's say we want to call the C function function_foo from a Python program. To do this, the Python interpreter needs to:

  • Find where the function is located. This probably means finding the binary generated by the C compiler which exports this function.

  • Load the code of the function in executable memory.

  • Convert the Python parameters to C-compatible parameters before calling the function.

  • Call the function with the right calling convention.

  • Convert the return values of the C function to Python-compatible variables to return them to the Python code.

现在,让我们看看从Python程序中调用C函数function_foo的话,Python解释器需要做的工作:
* 找到导出该函数的二进制文件;
* 将该函数的代码参加从二进制文件中加载到内存中;
* 在调用该函数前将Python参数转换为C兼容的参数;
* 使用正确的调用规则调用C函数;
* 将C函数的返回值转换为Python兼容的类型,然后将返回值返回给Python代码。
 

The process described above is pretty complex and there are a lot of ways to make it entirely automatic and transparent to C and Python programmers:

  • The first solution is to write by hand a lot of glue code, once for each function exported or imported, which does the Python-to-C parameter conversion and the C-to-Python return value conversion. This glue code is then linked with the interpreter which allows Python programs to call Python functions which delegate work to C functions.

  • Another, nicer solution is to automatically generate the glue code, once for each function exported or imported, with a special compiler which reads the original function signature.

  • The solution used by GLib is to use the GType library which holds at runtime a description of all the objects manipulated by the programmer. This so-called dynamic type [1] library is then used by special generic glue code to automatically convert function parameters and function calling conventions between different runtime domains.

上述流程非常复杂,并且需要大量的工作来让这个调用的过程完全自动化并且对C和Python程序员完全透明:
* 第一个解决方案是为每一个导入或导出的函数手写大量的胶水代码,用来进行从Python到C的参数转换和C到Python的返回值转换。这些胶水代码被链接到Python解释器中,允许Python程序直接调用用C语言实现的Python函数;
* 另一个更好的办法是使用一个特殊的编译器,解析原始的C语言函数,为每一个导出或导入的函数自动生成胶水代码;
* GLib所使用的方法是在运行时管理所有的对象,然后通用的胶水代码将使用一个动态类型库自动地在不同的运行时环境中进行函数参数和函数调用规则的转换。
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain boundaries is written once: the figure below states this more clearly.
GType所采用的解决方案的最大优势是在不同运行时之间的胶水代码只需要编写一次,如下图所示:
 
Currently, there exist at least Python and Perl generic glue code which makes it possible to use C objects written with GType directly in Python or Perl, with a minimum amount of work: there is no need to generate huge amounts of glue code either automatically or by hand.
当前至少存在Python和Perl的通用胶水代码,以使在Python和Perl中直接使用GType的C语言对象成为可能,并且所需的工作最少:没有必要再自动或手动地生成大量的胶水代码了。
 
Although that goal was arguably laudable, its pursuit has had a major influence on the whole GType/GObject library. C programmers are likely to be puzzled at the complexity of the features exposed in the following chapters if they forget that the GType/GObject library was not only designed to offer OO-like features to C programmers but also transparent cross-language interoperability.
尽管我们的目标是否值得称赞仍有争议,但我们所作的工作已经对整个GType和GObject库产生巨大的影响。GType/GObject库不仅仅设计来为C程序员提供面向对象的特性,它还用来使跨语言交互变得对开发者透明,如果C程序员忘记了这一点,那他很可能会杜接下来的章节所展现的复杂的特性感到困惑。
 
[1] There are numerous different implementations of dynamic type systems: all C++ compilers have one, Java and .NET have one too. A dynamic type system allows you to get information about every instantiated object at runtime. It can be implemented by a process-specific database: every new object created registers the characteristics of its associated type in the type system. It can also be implemented by introspection interfaces. The common point between all these different type systems and implementations is that they all allow you to query for object metadata at runtime.
注1:已经有大量不同的动态类型系统的实现:包括所有的C++编译器、Java、.NET等。动态类型系统允许你在运行时获取每一个实例化对象的信息。它可以被实现为与进程相关的数据库:每一个新的对象在类型系统中注册与它的类型相关的特性。动态类型系统也可以实现为接口内省。所有这些动态类型系统及其实现的共同点是,他们允许你在运行时查询每一个对象的元数据。

转载于:https://my.oschina.net/wsgalaxy/blog/3008507

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值