Python要想调用C语言写的动态连接库。不仅要兼容C接口的调用习惯,还须要兼容C语言的数据类型。幸运的是ctypes库已经做了这双方面的工作。以便调用动态连接库是很方便的。在Hello World的程序里,这行代码编写例如以下:

MessageBox = windll.user32.MessageBoxW

从这行代码的简洁程度来看。是很优美的。这样的优美是因为ctypes库在背后做了许多的工作。比方windll事实上是一个比較复杂的对象。在ctypes库里,它提供了三个easy载入动态连接库的对象:cdll、windll和oledll。通过訪问这三个对象的属性,就能够调用动态连接库的函数了。

当中cdll主要用来载入C语言调用方式(cdecl)。windll主要用来载入WIN32调用方式(stdcall),而oledll使用WIN32调用方式(stdcall)且返回值是Windows里返回的HRESULT值。假设你曾经没有学习过编程,肯定没有办法区分cdecl和stdcall,就算学习过编程,假设没有写过跨不同库之间的调用,也未必知道。因为在眼下IDE的开发环境下,已经所有隐藏这些的细节。

但在跨语言方面调用时,就不能忽略这样的细节了。那么你或许问为什么会出现这两种调用方式,不是同一个动态连接库吗?对于这个问题。问得好。

要回答这个问题,得从发明C语言那时候说起。

在70年代。美国人丹尼斯·里奇发明了C语言。而且使用C语言编写UNIX,由此他就成为了C语言之父和UNIX操作系统之父。因为UNIX操作系统很高效,改动起来也很方便,是得益于使用了C语言来编写。

随着UNIX操作系统的推广,C语言也变成了一个流行的语言。

要让UNIX变得高效率。那么C语言的设计上,就要着眼于高效的设计。

在函数调用这方面的设计,就体现了这一点。在C语言的函数调用时。须要传送多个參数。

这些參数的传送是能够通过寄存器或者栈来传送。那你或许问为什么不仅仅使用寄存器这一种方式呢?因为函数调用的參数比較多。比方达到5个。

而且在那时候的CPU的寄存器很少,也满足不了这个要求。不像眼下ARM或MIPS的CPU,寄存器比較多。多达13个之多。这时所有使用寄存器来传送參数是基本能够解决这个问题了。在当时的环境之下,设计的C语言的编译器都是按栈的方式来传递函数调用的參数,这样不但能够解决寄存器少的问题,也能够解决另外一个问题。就是能够动态地传递參数的个数。

上面仅仅是攻克了个数的问题,那又出现了另外一个问题,就是參数的入栈的顺序问题。这个好比像学校里体育老师叫一班学生来排队。排头是从高到矮,还是从矮到高的选择。在入栈这个问题上。C语言也面临两个选择。一个跟代码的书写的顺序一样从左到右,还有一个是从右到左。在考虑到动态參数的问题之后,C语言的设计者採用了从右到左的入栈方式,这样的方式有两个长处:一是函数执行时,默认方式是从左到右,意味着出栈的方向应优先为栈顶的元素,这样能够提高执行效率;二是函数參数不定时,执行时分析字符串里出现须要的參数,每出现一个參数就弹出栈一次,跟执行分析的顺序一致。比方以下的函数声明:

printf(const char *,...);

由上可见入栈的顺序不同,调用的方式就不一样。在C语言里都是採用从右向左的方式入栈。在PASCAL语言里是从左向右入栈顺序的。在ctypes库里cdll、windll和oledll都是支持从右到左入栈的參数顺序。

接着下来又引出来了另外一个问题,既然參数是採用入栈的方式来传递。那么就会出现这样的情况,当栈的參数没有使用到时,谁来清除。恢复栈的状态。

在这个问题上。在编译器的设计者里又出现了两种选择:一种是倾向调用者清除。一种是倾向被调用者清除。

这两种方式在性能上没有什么差别,仅仅是安排清除的代码在不同的位置上。cdll是使用调用者清除的栈的方式。而windll和oledll是使用被调用者清除。这点就是它们之间的差别。因此。Python里调用动态连接库时。一定要清楚每一个函数使用的调用方式,否则程序就会出问题。重则直接死掉。cdll和windll的差别例如以下图:

cdll和windll的差别的更多相关文章

  1. windll对象

    回过头来,再看一下windll和oledll的差别,这两者之间最大的差别是oledll调用的函数都是固定返回HRESULT类型的值,而windll是不固定的类型的.在Python 3.3版本号之前,都 ...

  2. ctypes 调用 dll

    1. 加载 Windows API 和 C 运行库 先看例子 from ctypes import * u32 = windll.LoadLibrary('user32.dll') #加载user32 ...

  3. python调用c\c++

    前言 python 这门语言,凭借着其极高的易学易用易读性和丰富的扩展带来的学习友好性和项目友好性,近年来迅速成为了越来越多的人们的首选.然而一旦拿python与传统的编程语言(C/C++)如来比较的 ...

  4. paip.java c# .net php python调用c++ c dll so windows api 总结

    paip.java c# .net  php python调用c++ c dll so windows api 总结 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来 ...

  5. ROLAP和MOLAP的概念和差别

    ROLAP和MOLAP的概念和差别OLAP(on-Line Analysis Processing)是使分析人员.管理人员或执行人员能够从多角度对信息进行快速.一致.交互地存取,从而获得对数据的更深入 ...

  6. apt-get upgarde和dist-upgrade的差别

    apt-get upgarde和dist-upgrade的差别 apt-get upgarde和dist-upgrade的差别   Debian/Ubuntu Linux都使用apt,升级时都是:  ...

  7. python与ruby的差别

    1.引用文件差别 Ruby:同一目录下的文件,如/usr/local/ruby/foo.rb与/usr/local/ruby/bar.rb两个文件.如果直接在foo.rb中 require 'bar' ...

  8. 【转】responseText,responseBody,responseXML差别

    为了做ajax的代理,研究了下服务器端的xmlhttp和客户端ajax中的xmlhttp,做了个比较 由于我一直使用JavaScript作为Asp的教本语言,所以比较起来更清楚.服务器端的xmlhtt ...

  9. 我的ORM之十二 -- 支持的数据库及差别

    我的ORM索引 支持最好的是SqlServer2005,Sqlserver2008,SqlServer2012 ,后续将支持:MySql,Sqlite,Oracle. 1.分页差别 MsSql 200 ...

随机推荐

  1. Android 内存管理(二)

    很多开发者都是从j2me或j2ee上过来的,对于内存的使用和理解并不是很到位,Android开发网本次给大家一些架构上的指导,防止出现豆腐渣工 程的出现.Android作为以Java语言为主的智能平台 ...

  2. PhpStorm快捷键设置/个性化设置,

    #常用快捷键 设置快捷键:File -> Settings -> IDE Settings -> Keymap -> 选择“Eclipse” -> 然后“Copy”一份 ...

  3. mysqldump使用

    mysqldump常用于MySQL数据库逻辑备份. 1.各种用法说明 A. 最简单的用法: mysqldump -uroot -pPassword [database name] > [dump ...

  4. 【转】android 最新 NDK r8 在window下开发环境搭建 安装配置与使用 详细图文讲解,完整实际配置过程记录(原创)

    原文网址:http://www.cnblogs.com/zdz8207/archive/2012/11/27/android-ndk-install.html android 最新 NDK r8 在w ...

  5. PostgreSql字符串函数和操作符

    本节描述了用于检查和操作字符串数值的函数和操作符.在这个环境中的字符串包括所有 character, character varying, text 类型的值.除非另外说明,所有下面列出的函数都可以处 ...

  6. 提示35. 怎样实现OfTypeOnly<TEntity>()这样的写法

    提示35. 怎样实现OfTypeOnly<TEntity>()这样的写法 如果你编写这样LINQ to Entities查询: 1 var results = from c in ctx. ...

  7. FAT32文件系统--For TF卡

    1. TF卡空间是如何分配的? 下面以4GB TF卡为例,通过WinHex工具进行分析,其空间分配如下图所示: FAT32把目录当做文件来管理,所以没有独立的目录区,所有的文件目录项都是在数据区里面的 ...

  8. 自动化测试(四):VBScript脚本语言

    VBS基于对象,只能利用现成的对象,不能封装.继承等,意味着不是真正的面向对象 语言的学习: 1.数据定义,变量定义,表达式 2.程序控制结构 3.函数,方法,类 4.异常处理 VBScript的数据 ...

  9. selenium在chrome上运行报 Element is not clickable at point (1096, 26)

    Firefox上正常运行的脚本在chrome上提示Element is not clickable at point (1096, 26).分析原因,首先肯定不是因为页面元素不存在而无法点击.也不是要 ...

  10. Java学习笔记(1)

    封装基本原则之一: 将实例变量标记为private,将getters与setters标记为public,用setters来检查参数并判断是否可以执行: 局部变量与实例变量的区别: 你无需初始实例变量, ...