zoukankan      html  css  js  c++  java
  • C++混合编程之idlcpp教程Python篇(2)

        在上一篇 C++混合编程之idlcpp教程(一) 中介绍了 idlcpp 工具的使用。现在对 idlcpp 所带的示例教程进行讲解,这里针对的 Python 语言的例子。首先看第一个示例程序 PythonTutorial0。像很多语言的第一个例子一样,是一个打印 Hello world 的程序。用Visual Studio 2015打开解决方案文件 tutorialsPythonTutorialsPythonTutorials.sln。其下已经有多个工程文件:

    在工程PythonTutorial0中,已经加入了三个文件:PythonTutorial0.cpp, Tutorial0.i, tutorial0.py。首先看Tutorial0.i内容如下:

    //tutorial
    
    ###include <stdio.h>
    
    namespace tutorial
    {
        struct Test
        {
            static void Run();
        };
        #{
        inline void Test::Run()
        {
            printf("Hello World!");
        }
        #}
    }

    和C++代码较为相似。编译Tutorial0.i,将会生成Tutorial0.h,Tutorial0.mh,Tutorial0.ic,Tutorial0.mc四个文件。其中Tutorial0.h内容如下:

    //DO NOT EDIT THIS FILE, it is generated by idlcpp
    //http://www.idlcpp.org
    
    #pragma once
    
    
    #include <stdio.h>
    
    
    #line 5 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
    namespace tutorial
    
    #line 6 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
    {
    
    #line 7 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
        struct Test
    
    #line 8 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
        {
        public:
    
    
    #line 9 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
            static void Run();
    
    #line 10 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
        };
    
        inline void Test::Run()
        {
            printf("Hello World!");
        }
        
    
    #line 17 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
    }

    因为在编译.i文件时指定了-ld选项,所以生成的.h文件中其中有许多#line指令,这是为下一步C++编译时能够定位错误到.i中的位置,而不是定位到.h上。修改编译选项,去掉-ld选项,重新编译,得到的结果如下:

    //DO NOT EDIT THIS FILE, it is generated by idlcpp
    //http://www.idlcpp.org
    
    #pragma once
    
    
    #include <stdio.h>
    
    namespace tutorial
    {
        struct Test
        {
        public:
    
            static void Run();
        };
    
        inline void Test::Run()
        {
            printf("Hello World!");
        }
        
    }

    这样看起来比较清爽了,请和上面的Tutorial0.i内容对照一下,基本上内容差不多。下面详细解释一下,首先是第一行

    //tutorial

    这是注释,idlcpp和C++一样用//表示单行注释,用/**/表示一块注释。

     ###include <stdio.h>

    idlcpp只分析接口的声明,而C++头文件中一般还会出现其他的内容。此处idlcpp提供了将.i文件中的部分内容直接复制到.h的方法,一共有三种

    1. ##,表示将后续的一整行复制到.h的相应位置上,类似C++中的//注释一行。
    2. #{ 和 #},将在这两个符号之间的内容复制到.h的相应位置上,类似C++中的/*和*/注释一大块。
    3. #,表示将后续的一个标识符或整数复制到相应的位置。

    这一行表示将#include <stdio.h>复制到.h中,下面的printf要用到这个头文件。

    namespace tutorial 以及对应的{}。

    namespace 和C++中的概念是一样的,会原样输出到.h中。

    struct Test 以及对应的{}; 。

    这个也和C++中概念类似,会原样输出到.h中。

    下面.h文件中多了一行

    public:

    在idlcpp中声明的数据成员以及成员函数都被认为是public的,所以此处无脑加了这一行。

    static void Run(); 

    这一行两边也是一样的,声明一个静态成员函数。

    #{

    inline void Test::Run()

    {

    printf("Hello World!");

    }

    #}

    如上所述,idlcpp将#{和#}之间的内容复制到.h中。因为idlcpp只处理函数声明,不能处理其实现代码,所以无法向C++一样将其实现代码放在类的声明中,只能写在外面。此处为了少写一个.cpp文件,就用内联函数的方式写在头文件中。

    文件Tutorial0.ic中没有实质性的内容。

    文件Tutorial0.mh和Tutorial0.mc用于构建对应的元数据信息,具体内容牵涉太多,暂时不做解释。

     再来看一下PythonTutorial0.cpp的内容

    #include <tchar.h>
    #include <windows.h>
    #include "Python.h"
    #include "../../../paf/src/pafpython/PythonWrapper.h"
    #include "../../Common/Tutorial0.h"
    #include "../../Common/Tutorial0.mh"
    #include "../../Common/Tutorial0.ic"
    #include "../../Common/Tutorial0.mc"
    
    
    #if defined(_DEBUG)
    #pragma comment(lib,"pafcore_d.lib")
    #pragma comment(lib,"pafpython_d.lib")
    #else
    #pragma comment(lib,"pafcore.lib")
    #pragma comment(lib,"pafpython.lib")
    #endif
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        const char* path = "tutorial0";
    
        PyImport_AppendInittab("pafpython", &PyInit_PafPython);
    
        Py_Initialize();
        PyObject* pName = PyUnicode_FromString(path);
        PyObject* pModule = PyImport_Import(pName);
        Py_DECREF(pName);
        if(pModule != NULL)
        {
            Py_DECREF(pModule);
        }
        else
        {
            PyErr_Print();
            fprintf(stderr, "Failed to load "%s"
    ", path);
        }
        Py_Finalize();
         return 0;
    }

    #include "Python.h"

    这一行引入Python头文件

     #include "../../../paf/src/pafpython/PythonWrapper.h"

    这一行引入Python插件头文件

    #include "../../Common/Tutorial0.h"

    #include "../../Common/Tutorial0.mh"

    #include "../../Common/Tutorial0.ic"

    #include "../../Common/Tutorial0.mc"

     这几行将由Tutorial0.i编译的结果包含进来,这样编译后就会将对应的元数据信息注册到系统中,从而能够让脚步语言访问到。

     main()函数中是一个运行一个Python脚步的基本过程。其中

    PyImport_AppendInittab("pafpython", &PyInit_PafPython);

    这一行在Python中加载插件。

    最后看一下tutorial0.py文件的内容

    import pafpython;
    paf = pafpython.paf;
    
    paf.tutorial.Test.Run();

    最后这句代码表示调用C++中的::tutorial::Test::Run(); 

    所有由idlcpp生成的数据类型都是在paf名字下,可以理解为Python中的名字pafpython.paf等价于C++中的全局名字空间。在C++中,Run函数的全名可以认为是::tutorial::Test::Run,在lua中即为pafpython.paf.tutorial.Test.Run。 编译链接后,执行结果如下图:

    可以看到Python正确调用了C++中的函数。

  • 相关阅读:
    计算机组成原理 04 认识各个硬件部件
    计算机组成原理 02 计算机的发展
    计算机组成原理 01 你好,计组
    蓝桥杯-2020-B组 &#183; 题解/解析(4/17)
    「HTML 5」1.HTML简介
    「易语言」主题颜色配置方案
    「易语言」那些年,我们经历的故事
    彻底解决Ubuntu中 “检测到系统程序错误”
    FFMPEG 的简单使用介绍 —— 合并音视频
    oh-my-zsh 中 agnoster主题 之 隐藏用户名信息
  • 原文地址:https://www.cnblogs.com/fdyjfd/p/5304098.html
Copyright © 2011-2022 走看看