colorful

zc qq:1337220912

 

2015年10月21日

Windows调试 - 如何使用dump文件

http://blog.csdn.net/jfkidear/article/details/22201829
 

Windows调试 - 如何使用dump文件

2013-02-04 16:05 445人阅读 评论(0) 收藏 举报
dmp dump debug visua

如何使用dump文件

我最近在开发一个windows下的程序(win7/win8),有一些case下会crash,如果在自己开发机器上调试比较简单:运行程序,然后vs attach到进程上即可,但是在每台QA的机器上安装vs时不现实的,因此我们要用到dump文件。

微软网站有一篇文章讲述如何创建dump文件:

http://support.microsoft.com/kb/931673

第一种: 通过任务管理器:这种适用在程序挂了(crash)的时候进程还未退出,比如我运行程序,出现了下面的错:


此时打开任务管理器,右击相应进程,点击"Create Dump File“:


一会创建完成:


然后把这个DMP文件拷到开发机器上,用VS打开: 会出现下面的界面,要想知道发生错误时候的调用栈,需要设置symbol的路径,点击”Set Symbol Paths“:


注意这个pdb要对应于crash的exe,否则调用栈没法显示:


设置完成后,点击”Debug with Native Only“ 你就可以看到调用栈了。


第二种: 改注册表

如果程序crash的时候没有框蹦出来,可以通过改注册表的设置让操作系统在程序crash的时候自动生成dump,并放到特定的目录下

 

  1. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps  
  2. Value Name = DumpType  
  3. Data type: REG_DWORD  
  4. Value Data = 1  

其中Value Data=1代表的含义是:

 

 

  1. 0 = Create a custom dump  
  2. 1 = Mini dump  
  3. 2 = Full dump  

设置完成后,crash发生时,操作系统生成dump,路径在%LOCALAPPDATA%\CrashDumps下,详细可以参考:

 

http://msdn.microsoft.com/en-us/library/bb787181%28v=VS.85%29.aspx

(完)

posted @ 2015-10-21 15:22 多彩人生 阅读(608) | 评论 (0)编辑 收藏

2015年10月14日

STL的remove函数和list的remove成员函数

http://www.cnblogs.com/kinuxroot/archive/2013/01/25/stl_remove_problem.html

今天看书刚刚看的,就记录下来吧。这可能是老生常谈了,权且作为一个警醒的例子吧。

大家都知道STL有两个非常重要的组成部分,容器和算法。

算法就是一个个的函数,通过迭代器和容器关联在一起,完成一些工作。

算法和容器的分离为程序设计提供了很大的灵活性,但是也带来了一些负面效果,下面我讲的这个问题就是一个例子。

STL的算法里有一个remove函数,而list自身也有一个remove函数,功能都是一样的,移除某一个元素,那我们应该使用哪一个呢?

看一下下面这段程序

复制代码
 1     list<int> numbers;  2   3     for ( int number = 0; number <= 6; number ++ ) {  4         numbers.push_front(number);  5         numbers.push_back(number);  6     }  7   8     copy(numbers.begin(), numbers.end(),  9             ostream_iterator<int>(cout, " ")); 10     cout << endl; 11  12     // remove algorithm will remove element but not erase the element from container 13     // it will return the logical desination of container 14     list<int>::iterator endOfNumbers = remove(numbers.begin(), numbers.end(), 3); 15  16     copy(numbers.begin(), numbers.end(), 17             ostream_iterator<int>(cout, " ")); 18     cout << endl;
复制代码

输出是什么呢?

第一行肯定是6 5 4 3 2 1 0 0 1 2 3 4 5 6,那么第二行会输出什么?

如果是没有仔细看过STL的人肯定会认为remove(number.begin(), numbers.end(), 3)会移除所有值为3的元素。所以输出是:6 5 4 2 1 0 0 1 2 4 5 6。

但是,我们看一下它真正的输出:

6 5 4 2 1 0 0 1 2 4 5 6 5 6

你可能会非常惊讶,为什么最后会多出5和6两个数呢?

我们来讲一下remove算法的原理。

remove算法工作时并不是直接把元素删除,而是用后面的元素替代前面的元素,也即是说如果我对1234这个序列remove 2,返回的序列是 1344(3被复制到2的位置,4被复制到3的位置)。

这样上面的例子就好解释了,那两个3的元素并没有被移除,而是用后面的元素覆盖了前面的元素。多出的那两个数没有被移除掉而已。

那么我们应该如何真正完成移除呢?remove函数会返回一个迭代器,那个迭代器是这个序列的逻辑终点,也即是我代码里的endOfNumbers,它指向倒数第二个5上。

于是我们要利用list的erase函数完成元素移除

numbers.erase(endOfNumbers, numbers.end());

这样我们就完成了我们的工作,稍稍有点曲折……

其实我们可以把这两步放在一起,比如如果我想接着移除所有值为2的元素

numbers.erase(remove(numbers.begin(), numbers.end(), 2), numbers.end());

这样我们就可以一步到位了。

但是这样好么?

不好。

大家会发现,remove函数的原理是复制而不是指针的移动(因为函数操纵的是迭代器,而C++的迭代器没有定义删除操作),这样会带来一个问题:我们使用list是因为它的修改的效率非常高,改变一下指针就可以了。而这里我们复制了元素,如果在vector中,可能还是高效的,因为vector无论如何都要复制,而对于list就不是如此了,会极度降低我们的效率。

那我们怎么办呢?

答案是使用list自己的remove函数

numbers.remove(1);

我们可以这样删除所有值为1的元素。

也即是说,如果要删除list中的元素,我们应该使用list的remove成员函数,而不是remove算法

小结

我们都知道,STL是一个效率、复用性、灵活性折衷的产物,其中效率至关重要,所以STL已经禁止了一些效率低的操作(比如list的随机访问),而鼓励你去使用其它的容器。

但是,在算法中,为了灵活性,STL还是会牺牲一些东西,比如我们这个例子。

个人觉得,STL作为C++标准库的一个组成部分,特点和C++本身一模一样,强大而复杂,有些地方难以理解,很多细节需要学习注意,我们要学会避免陷入某些陷阱之中,比如这个例子就是一个效率陷阱。

其它更多的陷阱是错误处理方面的,STL本身并没有规定过多的错误处理,大部分的错误处理都交给了我们,理由很简单:性能至上,如果一个东西自身没有错误检查,我们可以包装一个带错误检查的类;但是如果这个东西自身就带了错误检查,那么我们就没有任何方法提升它的效率了。这也是很多C和C++库的设计原则。

所以,很多时候,需要我们深入细节,然后再决定到底怎么做。因为C++就是如此:有很多路可以走,需要我们自己选择最好的一条路。

分类: C++

posted @ 2015-10-14 15:50 多彩人生 阅读(859) | 评论 (1)编辑 收藏

2015年4月21日

C++ 11 Lambda表达式

http://www.cnblogs.com/hujian/archive/2012/02/14/2350306.html
C++ 11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。Lambda的语法形式如下:
              [函数对象参数] (操作符重载函数参数) mutable或exception声明 ->返回值类型 {函数体}
      可以看到,Lambda主要分为五个部分:[函数对象参数]、(操作符重载函数参数)、mutable或exception声明、->返回值类型、{函数体}。下面分别进行介绍。
      一、[函数对象参数],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象 参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
           1、空。没有使用任何函数对象参数。
           2、=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
           3、&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
           4、this。函数体内可以使用Lambda所在类中的成员变量。
           5、a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
           6、&a。将a按引用进行传递。
           7、a, &b。将a按值进行传递,b按引用进行传递。
           8、=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
           9、&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
      二、(操作符重载函数参数),标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
      三、mutable或exception声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意 是能修改拷贝,而不是值本身)。exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)。
      四、->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
      五、{函数体},标识函数的实现,这部分不能省略,但函数体可以为空。
      下面给出了一段示例代码,用于演示上述提到的各种情况,代码中有简单的注释可作为参考。
复制代码
class CTest
{
public:
 CTest() : m_nData(20) { NULL; }
 void TestLambda()
 {
  vector<int> vctTemp;
  vctTemp.push_back(1);
  vctTemp.push_back(2);

  // 无函数对象参数,输出:1 2
  {
   for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; });
  }

  // 以值方式传递作用域内所有可见的局部变量(包括this),输出:11 12
  {
   int a = 10;
   for_each(vctTemp.begin(), vctTemp.end(), [=](int v){ cout << v+a << endl; });
  }

  // 以引用方式传递作用域内所有可见的局部变量(包括this),输出:11 13 12
  {
   int a = 10;
   for_each(vctTemp.begin(), vctTemp.end(), [&](int v)mutable{ cout << v+a << endl; a++; });
   cout << a << endl;
  }

  // 以值方式传递局部变量a,输出:11 13 10
  {
   int a = 10;
   for_each(vctTemp.begin(), vctTemp.end(), [a](int v)mutable{ cout << v+a << endl; a++; });
   cout << a << endl;
  }

  // 以引用方式传递局部变量a,输出:11 13 12
  {
   int a = 10;
   for_each(vctTemp.begin(), vctTemp.end(), [&a](int v){ cout << v+a << endl; a++; });
   cout << a << endl;
  }

  // 传递this,输出:21 22
  {
   for_each(vctTemp.begin(), vctTemp.end(), [this](int v){ cout << v+m_nData << endl; });
  }

  // 除b按引用传递外,其他均按值传递,输出:11 12 17
  {
   int a = 10;
   int b = 15;
   for_each(vctTemp.begin(), vctTemp.end(), [=, &b](int v){ cout << v+a << endl; b++; });
   cout << b << endl;
  }


  // 操作符重载函数参数按引用传递,输出:2 3
  {
   for_each(vctTemp.begin(), vctTemp.end(), [](int &v){ v++; });
   for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; });
  }

  // 空的Lambda表达式
  {
   [](){}();
   []{}();
  }
 }

private:
 int m_nData;
};
复制代码

posted @ 2015-04-21 10:39 多彩人生 阅读(474) | 评论 (0)编辑 收藏

2015年3月1日

qcjl lua project log

2015/3/1
protoc-gen-lua 生成的lua又发现新的问题, main function has more than 200 local variables问题,网上搜索了一下,有相应的解决方法,据说还会有一个新的问题出来:不能用 repeated submessage,  建议用云风的pbc. 所以方案改为用云风的pbc

posted @ 2015-03-01 11:55 多彩人生 阅读(1556) | 评论 (0)编辑 收藏

2015年2月12日

cocos2dx lua protobuf

http://blog.csdn.net/weyson/article/details/17024325
http://www.cppblog.com/colorful/archive/2015/01/17/209557.html
http://blog.csdn.net/w00w12l/article/details/39316321

protoc-gen-lua下载地址: https://github.com/sean-lin/protoc-gen-lua

1/ 先到protobuf的python目录下执行
    python setup.py build
    python setup.py install

2/ 在protoc-gen-lua的plugin目录中新建protoc-gen-lua.bat, 内容如下:
@python 目录\protoc-gen-lua\plugin\protoc-gen-lua

3/ 用protoc把proto文件生成lua文件
  protoc --lua_out=./ --plugin=protoc-gen-lua="目录\protoc-gen-lua.bat"  test.proto

4/ 将protoc-gen-lua/protobuf下的pb.c 放到工程的Classes下, 并加入到c++工程中

5/ 将protoc-gen-lua/protobuf上的所有lua文件放到工程的src目录(lua目录)下

6/ AppDelegate.cpp 添加代码
extern "C"{
    int luaopen_pb(lua_State* L);
}
在applicationDidFinishLaunching()中调用 luaopen_pb(state);

---------------------------------------------------------------------------
    require "src/xy/person_pb"  
    local msg = person_pb.Person()  
    msg.id = 100   
    msg.name = "foo"   
    msg.email = "bar"   

    local pb_data = msg:SerializeToString()  -- Parse Example  
    print("create:", msg.id, msg.name, msg.email, pb_data)  


    local msg = person_pb.Person()   
    msg:ParseFromString(pb_data)   
    print("parser:", msg.id, msg.name, msg.email, pb_data)

---------------------------------------------------------------------------
移植到android 记得将pb.c添加到proj.android\jni\Android.mk中

 

posted @ 2015-02-12 11:42 多彩人生 阅读(1520) | 评论 (0)编辑 收藏

2015年2月6日

error C2061: 语法错误: 标识符“wctomb”

1>  pb.c
1>e:\test003\test101\src\pb.c : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(18): error C2054: 在“using”之后应输入“(”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(18): error C2061: 语法错误: 标识符“using”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(19): error C2061: 语法错误: 标识符“using”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(19): error C2061: 语法错误: 标识符“abs”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(19): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(19): error C2061: 语法错误: 标识符“atexit”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(20): error C2061: 语法错误: 标识符“atof”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(20): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(20): error C2061: 语法错误: 标识符“atoi”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(20): error C2061: 语法错误: 标识符“atol”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(21): error C2061: 语法错误: 标识符“bsearch”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(21): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(21): error C2061: 语法错误: 标识符“calloc”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(21): error C2061: 语法错误: 标识符“div”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(22): error C2061: 语法错误: 标识符“exit”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(22): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(22): error C2061: 语法错误: 标识符“free”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(23): error C2061: 语法错误: 标识符“labs”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(23): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(23): error C2061: 语法错误: 标识符“ldiv”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(23): error C2061: 语法错误: 标识符“malloc”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(24): error C2061: 语法错误: 标识符“mblen”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(24): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(24): error C2061: 语法错误: 标识符“mbstowcs”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(24): error C2061: 语法错误: 标识符“mbtowc”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(25): error C2061: 语法错误: 标识符“qsort”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(25): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(25): error C2061: 语法错误: 标识符“rand”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(25): error C2061: 语法错误: 标识符“realloc”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(26): error C2061: 语法错误: 标识符“srand”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(26): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(26): error C2061: 语法错误: 标识符“strtod”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(26): error C2061: 语法错误: 标识符“strtol”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(27): error C2061: 语法错误: 标识符“strtoul”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(27): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(28): error C2061: 语法错误: 标识符“wcstombs”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(28): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(28): error C2061: 语法错误: 标识符“wctomb”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(30): error C2054: 在“using”之后应输入“(”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(33): error C2061: 语法错误: 标识符“using”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(34): error C2061: 语法错误: 标识符“system”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(34): error C2059: 语法错误:“;”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(37): error C2061: 语法错误: 标识符“atoll”
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\cstdlib(37): error C2059: 语法错误:“;”
解决方法:
右击.c文件,c/c++/高级,强制包含文件,如果有algorithm或者其他的,去掉,重新编译

posted @ 2015-02-06 10:37 多彩人生 阅读(3348) | 评论 (0)编辑 收藏

2015年2月5日

fatal error C1853: "Debug\sift.pch"预编译头文件来自编译器的早期版本

该错误是因为当项目中混合了 .cpp 和 .c 文件时,编译器会对它们采取不同的编译方式(主要是因为对函数声明的处理方式不同),
因而不能共用一个预编译头文件。在 VC++ 中,默认的预编译头文件是针对 C++ 的 (stdafx.h 和 stdafx.cpp),当然也可以创建针对 C 的预编译头。

方法:将少数的不同类文件设为不使用预编译头是比较平衡的做法,方法是:对于 VC++6.0,在 FileView 里对要取消预编译头的 .c (或 .cpp) 文件点右键,
选择 settings,在弹出的对话框右边选择 category 为 precompiled headers,再设置选项为 not using ...;
(对于 VS2005,则在 solution explorer 中对相应文件点右键选择 properties,在 precompiled headers 项下设置 not using... 即可。如果需要设置多个文件,
则可以按住 Ctrl 键再同时选中这些文件并设置)
PS:解释如下点击项目 点击属性 然后选择C/C++ 预编译头 创建使用头文件 不使用预编译头文件
(解决方案资源管理器-右击需要排除的c或cpp文件]-弹出属性菜单-展开C/C++-预编译头-创建/使用预编译头-选择不适用预编译头)

posted @ 2015-02-05 18:32 多彩人生 阅读(12484) | 评论 (0)编辑 收藏

error C2275: “XXX”: 将此类型用作表达式非法

在移植c++代码到c的时候,经常会出现一个奇怪的错误,
error C2275: “XXX”: 将此类型用作表达式非法

表达式非法,这个错误是由于c的编译器要求将变量的申明放在一个函数块的头部,而c++没有这样的要求造成的。


解决的办法就是把变量的申明全部放在变量的生存块的开始。

posted @ 2015-02-05 18:30 多彩人生 阅读(6791) | 评论 (0)编辑 收藏

2015年1月17日

Quick-Cocos2d-x 集成 Google protobuf 方法

http://cn.cocos2d-x.org/tutorial/show?id=506

本文将向您介绍Quick-Cocos2d-x集成google protobuf的方法。  
 
第一步   需要最新的protobuf 类库和解析程序。 
下载地址:https://github.com/sean-lin/protoc-gen-lua
 
git clone https://github.com/sean-lin/protoc-gen-lua.git 到任意的一个地方
 

然后,可以得到重要的两个目录

1
2
protoc-gen-lua/plugin/ 
protoc-gen-lua/protobuf/
 
第二步, 需要使用protoc —lua_out=. 这种方法, 将我们自己的*.proto 的文件解析成lua文件

plugin目录是提供将buffer 文件解析成lua 版本的类库, 需要python 支持。  如果已经编译了google 官方的protoc 那个程序, 只需要在系统PATH环境变量总追加plugin目录就好:

1
export PATH={protoc-gen-lua DIR }/plugin:$PATH
 
关于protoc的编译另请google .
 
如果解析不出lua文件来, 可以手动志信一下plugin/protoc-gen-lua的程序, 他应该是+x 的权限(chmod +x plugin/protoc-gen-lua)
 
细节的安装步骤可以参考 https://code.google.com/p/protoc-gen-lua/
 
第三步 , 将protobuf 集成到quick 中
protoc-gen-lua/protobuf/ 目录就是要编译到quick-cocos2d-x目录里面的部分。 
 
现在, 我们只需要 protoc-gen-lua/protobuf/pb.c 这个文件 
 

先确定自己的quick-cocos2d-x lua扩展目录:

1
/quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/
 
所有lua 的c/c++现成扩展,都可以直接放到这里。 
  
将pb.c这个文件复制到 lua_extension目录下, 最好独立一个目录, 免得扩展多了乱。 
  

这是我的目录结构:

1
./quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/protobuf/pb.c
  
然后开始修改扩展程序配置文件, lua_extensions.c
 

路径为:

1
./quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/lua_extensions.c
 

目前是一个不足60行的小文件, 我打算全部贴进来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "lua_extensions.h" 
   
#if __cplusplus 
extern "C"
#endif 
    
// cjson 
#include "cjson/lua_cjson.h" 
    
    
// zlib 
#include "zlib/lua_zlib.h" 
    
    
// lpack 
#include "lpack/lpack.h" 
    
    
// socket 
#include "socket/luasocket.h" 
#include "socket/mime.h" 
#include "socket/socket_scripts.h" 
    
    
// filesystem 
#include "filesystem/lfs.h" 
    
    
// lsqlite3 
#include "lsqlite3/lsqlite3.h" 
    
    
#include "protobuf/pb.c"   //引用protobuf 库文件 
    
    
static luaL_Reg luax_exts[] = { 
     {"cjson", luaopen_cjson_safe}, 
     {"zlib", luaopen_zlib}, 
     {"pack", luaopen_pack}, 
     {"socket.core", luaopen_socket_core}, 
     {"mime.core", luaopen_mime_core}, 
     {"lfs", luaopen_lfs}, 
     {"lsqlite3", luaopen_lsqlite3}, 
     {NULL, NULL} 
}; 
    
    
void luaopen_lua_extensions(lua_State *L) 
     // load extensions 
     luaL_Reg* lib = luax_exts; 
     lua_getglobal(L, "package"); 
     lua_getfield(L, -1, "preload"); 
     for (; lib->func; lib++) 
     
         lua_pushcfunction(L, lib->func); 
         lua_setfield(L, -2, lib->name); 
     
     lua_pop(L, 2); 
    
    
     // load extensions script 
     luaopen_socket_scripts(L); 
     luaopen_pb(L);   //这是加入的protobuf 扩展注册名 
    
    
#if __cplusplus 
} // extern "C" 
#endif
至此 , protobuf 扩展部分就算扩展完成了。 
 
确认是否成功支持 , 可以在quick 项目最先被调用的lua文件中追加 require "pb" 做测试。 
 
*但这时候通过protoc 转码后得到的lua文件还不能被解析。 
 
第四步 从项目中包含protobuf的 lua库
protoc-gen-lua/protobuf/这个目录下面, 还有大量的.lua文件, 是用来支持proto转码后的文件解析调用的。 不能少了这些文件。 
 
复制protoc-gen-lua/protobuf文件夹 到项目中 scripts目录下。  
  

目录结构应该是这样的:

1
[PROJECT]/scripts/protobuf/*.lua
 
然后, 需要告诉框架,从哪里可以引用到它。 
 

修改main.lua 在require("appxxxxxx") 上面 , 加入下面的代码:

1
package.path = package.path .. ";./protobuf/?.lua;./scripts/protobuf/?.lua;"
 
这个方法, 能保证程序在被编译到手机之后仍然可以继续访问这个库。 
  
***千万别把转码的proto文件放到[PROJECT]/scripts/protobuf 目录里面.不信可以试试。
 
现在, 项目支持protobuf 文件的解析了。
 
第五步  重新编译player-x
如果不习惯用player-x调试, 这个步骤不是必须的。 
 

进入player-x qt源码目录 :

1
cd quick-cocos2d-x/player/proj.qt
 

使用qmake 文件执行quick-x.pro 文件 

1
qmake ./quick-x.pro
 
继续:
make 
 
等待结束, 将得到的quick-x-player文件, 
 
放到:quick-cocos2d-x/player/bin/mac/ 目录下, 这样sublime text 装QuickXDev 扩展的直接可以用。 
  
**如果是mac os 10.9 系统, 可能编译不过去player-x程序。 我遇到了这个问题。 
 
会提示错误  pb.c:28:10: fatal error: 'endian.h' file not found 
 

如果错误信息相同, 修改文件:

1
./quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/protobuf/pb.c
 

查找行:

1
#include <endian.h>
  

临时变更为:

1
#include <machine/endian.h>
  
然后重新编译 player-x 
 
make 就足够了 
 
make
 
**player-x 编译完毕后, 千万要将endian.h 引用改回原来的 #include <endian.h> , 否则打包到手机的时候又回提示文件找不到了。 

posted @ 2015-01-17 16:08 多彩人生 阅读(1909) | 评论 (0)编辑 收藏

Lua注册回调到C++

http://cn.cocos2d-x.org/tutorial/show?id=1896

思路

像所有语言一样,绑定回调主要是执行的任务执行到特定情形的时候,调用对用回调方法。 本文也一样,Lua注册回调到C++的核心思路是,当C代码执行到特定特定情形的时候,调用Lua的方法。

我这里使用的是用lua_stack直接调用lua的方法,没有使用Cocos2d-x封装的那个dispatcher,因为熟悉那个格式太墨迹了。


主要步骤如下

  • 缓存Lua函数在Lua环境中的引用

  • 在C代码的地方用C的方式设置好回调

  • 在C代码回调函数执行的时候,调用lua函数


实现

  • C代码绑定回调,调用Lua函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void ArmatureNode::registerMovementEventHandler(int handler)
{
    unregisterMovementEventHandler();  //移除之前注册的监听
    _movementHandler = handler;         //缓存lua函数的引用 这个后边说
     
    auto dispatcher = getCCEventDispatcher();
     
    auto f = [this](cocos2d::EventCustom *event) //注册c代码形式的回调 这里用function做
    {
        auto eventData = (dragonBones::EventData*)(event->getUserData());
        auto type = (int) eventData->getType();
        auto movementId = eventData->animationState->name;
        auto lastState = eventData->armature->getAnimation()->getLastAnimationState();
         
        auto stack = cocos2d::LuaEngine::getInstance()->getLuaStack();
        stack->pushObject(this"db.ArmatureNode");
        stack->pushInt(type);
        stack->pushString(movementId.c_str(), movementId.size());        
        //通过LuaStack调用lua里的函数    最后一个参数设置参数个数
        stack->executeFunctionByHandler(_movementHandler, 3);
    };
     
    dispatcher->addCustomEventListener(dragonBones::EventData::COMPLETE, f);
}
void ArmatureNode::unregisterMovementEventHandler(void)
{
    if (0 != _movementHandler)
    {
        cocos2d::LuaEngine::getInstance()->removeScriptHandler(_movementHandler); //移除lua函数的绑定
        _movementHandler = 0;
    }
}
  • 提供Lua函数绑定到C的方法   

上边的这个函数直接用cocos里的genbinding.py 是无法正确生成Lua里可调用的接口的,需要手动编写绑定方法.

说这个得用到Cocos2d-x中提供的一个方法:toluafix_ref_function会把一个Lua栈中的方法转成一个int,以便C++中调用。我会在最后面说这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int tolua_db_DBCCArmature_registerMovementEventHandler(lua_State* tolua_S)
{
    if (NULL == tolua_S)
        return 0;
    int argc = 0;
     
    dragonBones::ArmatureNode* self = nullptr;
    self = static_cast<dragonBones::ArmatureNode*>(tolua_tousertype(tolua_S,1,0)); //第一个参数 就是lua里的self
     
    argc = lua_gettop(tolua_S) - 1;
     
    if (1 == argc)
    {
        //第二个参数,就是Lua里的function 这里要通过toluafix_ref_function这个函数映射成一个Int值
        int handler = (toluafix_ref_function(tolua_S,2,0)); 
        self->registerMovementEventHandler(handler);
         
        return 0;
    }
    return 0;
}

 

  • 将绑定方法绑定到Lua环境里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int extends_ArmatureNode(lua_State* tolua_S)
{
    lua_pushstring(tolua_S, "db.ArmatureNode");//之前db.ArmatureNode是通过脚本绑定在lua里。这里只做扩展
    lua_rawget(tolua_S, LUA_REGISTRYINDEX);
    if (lua_istable(tolua_S,-1))
    {
        lua_pushstring(tolua_S,"registerMovementEventHandler");
        lua_pushcfunction(tolua_S,tolua_db_DBCCArmature_registerMovementEventHandler);
        lua_rawset(tolua_S,-3);
    }
     
    lua_pop(tolua_S, 1);
    return 0;
}
  • Lua里设置回调到C++

1
2
3
4
5
6
7
8
 local arm = db.ArmatureNode:create("Dragon")
    local animation = arm:getAnimation()
    animation:gotoAndPlay("walk")
    arm:registerMovementEventHandler(
        function(...)
            print(...) 
        end
    )


-测试

打印回调输出,测试通过 userdata 8 walk


其他

  • toluafix_ref_function 以及 toluafix_get_function_by_refid

这 两个方法是相互对应的 toluafix_ref_function这个方法在注册表上将一个lua的function与一个function_id生成映射 toluafix_get_function_by_refid 方法可以通过前一个方法生成的function_id来讲绑定的lua function放到栈顶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
TOLUA_API int toluafix_ref_function(lua_State* L, int lo, int def)
{
    if (!lua_isfunction(L, lo)) return 0;
    s_function_ref_id++;                            //function_id 加1
    lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING);//在注册表上,存放luafunction 映射table 的key压栈
    lua_rawget(L, LUA_REGISTRYINDEX);               //获取方法映射表,放在栈顶
    lua_pushinteger(L, s_function_ref_id);          //function_id压栈
    lua_pushvalue(L, lo);                           //lo有效处索引处是lua方法,lua方法拷贝,压栈
 
 
    lua_rawset(L, -3);                        //生成映射 
    lua_pop(L, 1);                                              
    return s_function_ref_id;
}
TOLUA_API void toluafix_get_function_by_refid(lua_State* L, int refid)
{
    lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING);            //存放luafunction 映射table 的key压栈
    lua_rawget(L, LUA_REGISTRYINDEX);                           //获取方法映射表,放在栈顶
    lua_pushinteger(L, refid);                                  //function_id压栈
    lua_rawget(L, -2);                                          //获取到的luafunction 放到栈顶
    lua_remove(L, -2);                                          //
}
  • executeFunctionByHandler

executeFunctionByHandler 这个方法只是通过toluafix_get_function_by_refid 获取到function然后通过lua_pcall 方法调用,代码就不写了。

posted @ 2015-01-17 11:12 多彩人生 阅读(2787) | 评论 (0)编辑 收藏

仅列出标题  下一页

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜