如何使用dump文g
我最q在开发一个windows下的E序(win7/win8)Q有一些case下会(x)crashQ如果在自己开发机器上调试比较单:(x)q行E序Q然后vs attach到进E上卛_Q但是在每台QA的机器上安装vs时不现实的,因此我们要用到dump文g?/p>
微Y|站有一文章讲q如何创建dump文gQ?br />
http://support.microsoft.com/kb/931673
W一U:(x) 通过d理?/strong>Q这U适用在程序挂?crash)的时候进E还未退出,比如我运行程序,出现了下面的错:(x)
此时打开d理器,叛_相应q程Q点?Create Dump File“Q?br />
一?x)创建完成?x)
然后把这个DMP文g拷到开发机器上Q用VS打开Q??x)出C面的界面Q要想知道发生错误时候的调用栈,需要设|symbol的\径,点击”Set Symbol Paths“Q?br />
注意q个pdb要对应于crash的exeQ否则调用栈没法昄Q?/p>
讄完成后,点击”Debug with Native Only“ 你就可以看到调用栈了?/p>
W二U:(x) Ҏ(gu)册表
如果E序crash的时候没有框y出来,可以通过Ҏ(gu)册表的设|让操作pȝ在程序crash的时候自动生成dumpQƈ攑ֈ特定的目录下
http://msdn.microsoft.com/en-us/library/bb787181%28v=VS.85%29.aspx
Q完Q?/p>
今天看书刚刚看的Q就记录下来吧。这可能是老生常谈了,权且作ؓ(f)一个警醒的例子吧?/p>
大家都知道STL有两个非帔R要的l成部分Q容器和法?/p>
法是一个个的函敎ͼ通过q代器和容器兌在一P完成一些工作?/p>
法和容器的分离为程序设计提供了很大的灵zL,但是也带来了一些负面效果,下面我讲的这个问题就是一个例子?/p>
STL的算法里有一个remove函数Q而list自n也有一个remove函数Q功能都是一L(fng)Q移除某一个元素,那我们应该用哪一个呢Q?/p>
看一下下面这D늨?/p>
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;
输出是什么呢Q?/p>
W一行肯定是6 5 4 3 2 1 0 0 1 2 3 4 5 6Q那么第二行?x)输Z么?
如果是没有仔l看qSTL的h肯定?x)认为remove(number.begin(), numbers.end(), 3)?x)移除所有gؓ(f)3的元素。所以输出是Q? 5 4 2 1 0 0 1 2 4 5 6?/p>
但是Q我们看一下它真正的输出:(x)
6 5 4 2 1 0 0 1 2 4 5 6 5 6
你可能会(x)非常惊讶Qؓ(f)什么最后会(x)多出5?两个数呢Q?/p>
我们来讲一下remove法的原理?/p>
remove法工作?strong>q不是直接把元素删除Q而是用后面的元素替代前面的元?/strong>Q也x说如果我?234q个序列remove 2Q返回的序列?1344Q?被复制到2的位|,4被复制到3的位|)?/p>
q样上面的例子就好解释了Q那两个3的元素ƈ没有被移除,而是用后面的元素覆盖了前面的元素。多出的那两个数没有被移除掉而已?/p>
那么我们应该如何真正完成U除呢?remove函数?x)返回一个P代器Q那个P代器是这个序列的逻辑l点Q也x我代码里的endOfNumbersQ它指向倒数W二?上?/p>
于是我们要利用list的erase函数完成元素U除
numbers.erase(endOfNumbers, numbers.end());
q样我们完成了我们的工作,E稍有点曲折……
其实我们可以把这两步攑֜一P比如如果我想接着U除所有gؓ(f)2的元?/p>
numbers.erase(remove(numbers.begin(), numbers.end(), 2), numbers.end());
q样我们可以一步到位了?/p>
但是q样好么Q?/p>
不好?/p>
大家?x)发玎ͼremove函数的原理是复制而不是指针的UdQ因为函数操U늚是P代器Q而C++的P代器没有定义删除操作Q,q样?x)带来一个问题:(x)我们使用list是因为它的修改的效率非常高,改变一下指针就可以了。而这里我们复制了元素Q如果在vector中,可能q是高效的,因ؓ(f)vector无论如何都要复制Q而对于list׃是如此了Q?strong>?x)极度降低我们的效率?/strong>
那我们怎么办呢Q?/p>
{案是用list自己的remove函数
numbers.remove(1);
我们可以q样删除所有gؓ(f)1的元素?/p>
也即是说Q如果要删除list中的元素Q?strong>我们应该使用list的remove成员函数Q而不是remove法Q?/p>
结
我们都知道,STL是一个效率、复用性、灵zL折L(fng)产物Q其中效率至关重要,所以STL已经止了一些效率低的操作(比如list的随问)Q而鼓׃M用其它的容器?/p>
但是Q?strong>在算法中Qؓ(f)了灵zL,STLq是?x)牺牲一些东?/strong>Q比如我们这个例子?/p>
个h觉得QSTL作ؓ(f)C++标准库的一个组成部分,特点和C++本n一模一P强大而复杂,有些地方难以理解Q很多细节需要学?fn)注意,我们要学会(x)避免陷入某些陷׃中,比如q个例子是一个效率陷阱?/p>
其它更多的陷阱是错误处理斚w的,STL本nq没有规定过多的错误处理Q大部分的错误处理都交给了我们,理由很简单:(x)性能至上Q如果一个东西自w没有错误检查,我们可以包装一个带错误查的c;但是如果q个东西自n带了错误检查,那么我们没有Q何方法提升它的效率了。这也是很多C和C++库的设计原则?/p>
所以,很多时候,需要我们深入细?/strong>Q然后再军_到底怎么做。因为C++是如此Q有很多路可以走Q需要我们自己选择最好的一条\?/p>
该错误是因ؓ(f)当项目中混合?.cpp ?.c 文gӞ~译器会(x)对它们采取不同的~译方式Q主要是因ؓ(f)对函数声明的处理方式不同Q,
因而不能共用一个预~译头文件。在 VC++ 中,默认的预~译头文件是针对 C++ ?(stdafx.h ?stdafx.cppQ,当然也可以创建针?C 的预~译头?br />
Ҏ(gu)Q将数的不同类文g设ؓ(f)不用预~译头是比较q的做法,Ҏ(gu)是:(x)对于 VC++6.0Q在 FileView 里对要取消预~译头的 .c (?.cpp) 文g点右键,
选择 settingsQ在弹出的对话框双选择 category ?precompiled headersQ再讄选项?not using ...Q?br />Q对?VS2005Q则?solution explorer 中对相应文g点右键选择 propertiesQ在 precompiled headers 下讄 not using... 卛_。如果需要设|多个文Ӟ
则可以按?Ctrl 键再同时选中q些文gq设|)
PSQ解释如下点击项?点击属?然后选择C/C++ 预编译头 创徏使用头文?不用预~译头文?br />Q解x案资源管理器-叛_需要排除的c或cpp文g]-弹出属性菜?展开C/C++-预编译头-创徏/使用预编译头-选择不适用预编译头Q?/pre>
]]>
然后Q可以得到重要的两个目录
1 2 | protoc-gen-lua/plugin/ protoc-gen-lua/protobuf/ |
plugin目录是提供将buffer 文g解析成lua 版本的类库, 需要python 支持? 如果已经~译了google 官方的protoc 那个E序Q?只需要在pȝPATH环境变量总追加plugin目录好:
1 | export PATH={protoc-gen-lua DIR }/plugin:$PATH |
先确定自qquick-cocos2d-x lua扩展目录Q?
1 | /quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/ |
q是我的目录l构:
1 | ./quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/protobuf/pb.c |
路径为:(x)
1 | ./quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/lua_extensions.c |
目前是一个不?0行的文Ӟ 我打全部脓(chung)q来Q?
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 库文?nbsp; 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); //q是加入的protobuf 扩展注册?nbsp; } #if __cplusplus } // extern "C" #endif |
目录l构应该是这L(fng)Q?
1 | [PROJECT]/scripts/protobuf/*.lua |
修改main.lua 在require("appxxxxxx") 上面 Q?加入下面的代码:(x)
1 | package.path = package.path .. ";./protobuf/?.lua;./scripts/protobuf/?.lua;" |
q入player-x qt源码目录 Q?
1 | cd quick-cocos2d-x/player/proj.qt |
使用qmake 文g执行quick-x.pro 文g
1 | qmake ./quick-x.pro |
如果错误信息相同Q?修改文g:
1 | ./quick-cocos2d-x/lib/cocos2d-x/scripting/lua/lua_extensions/protobuf/pb.c |
查找?
1 | #include <endian.h> |
临时变更为:(x)
1 | #include <machine/endian.h> |
思\
像所有语a一Pl定回调主要是执行的d执行到特定情形的时候,调用对用回调Ҏ(gu)?本文也一PLua注册回调到C++的核心思\是,当C代码执行到特定特定情形的时候,调用Lua的方法?/p>
我这里用的是用lua_stack直接调用lua的方法,没有使用Cocos2d-x装的那个dispatcherQ因为熟(zhn)那个格式太墨迹了?/p>
主要步骤如下
~存Lua函数在Lua环境中的引用
在C代码的地方用C的方式设|好回调
在C代码回调函数执行的时候,调用lua函数
实现
C代码l定回调Q调用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(); //U除之前注册的监?/code> _movementHandler = handler; //~存lua函数的引?nbsp;q个后边?/code> auto dispatcher = getCCEventDispatcher(); auto f = [ this ](cocos2d::EventCustom *event) //注册c代码形式的回?nbsp;q里用function?/code> { 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里的函数 最后一个参数设|参C?/code> stack->executeFunctionByHandler(_movementHandler, 3); }; dispatcher->addCustomEventListener(dragonBones::EventData::COMPLETE, f); } void ArmatureNode::unregisterMovementEventHandler( void ) { if (0 != _movementHandler) { cocos2d::LuaEngine::getInstance()->removeScriptHandler(_movementHandler); //U除lua函数的绑?/code> _movementHandler = 0; } } |
提供Lua函数l定到C的方?
上边的这个函数直接用cocos里的genbinding.py 是无法正生成Lua里可调用的接口的Q需要手动编写绑定方?
说这个得用到Cocos2d-x中提供的一个方法:(x)toluafix_ref_function?x)把一个Lua栈中的方法{成一个intQ以便C++中调用。我?x)在最后面说这?/p>
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)); //W一个参?nbsp;是lua里的self argc = lua_gettop(tolua_S) - 1; if (1 == argc) { //W二个参敎ͼ是Lua里的function q里要通过toluafix_ref_functionq个函数映射成一个Int?/code> int handler = (toluafix_ref_function(tolua_S,2,0)); self->registerMovementEventHandler(handler); return 0; } return 0; } |
绑定方法绑定到Lua环境?/p>
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是通过脚本l定在lua里。这里只做扩?/code> 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 ) |
-试
打印回调输出Q测试通过 userdata 8 walk
其他
toluafix_ref_function 以及(qing) toluafix_get_function_by_refid
q?两个Ҏ(gu)是相互对应的 toluafix_ref_functionq个Ҏ(gu)在注册表上将一个lua的function与一个function_id生成映射 toluafix_get_function_by_refid Ҏ(gu)可以通过前一个方法生成的function_id来讲l定的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 ? lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING); //在注册表上,存放luafunction 映射table 的key压栈 lua_rawget(L, LUA_REGISTRYINDEX); //获取Ҏ(gu)映射表,攑֜栈顶 lua_pushinteger(L, s_function_ref_id); //function_id压栈 lua_pushvalue(L, lo); //lo有效处烦引处是luaҎ(gu)QluaҎ(gu)拯Q压?/code> 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); //获取Ҏ(gu)映射表,攑֜栈顶 lua_pushinteger(L, refid); //function_id压栈 lua_rawget(L, -2); //获取到的luafunction 攑ֈ栈顶 lua_remove(L, -2); // } |
executeFunctionByHandler
executeFunctionByHandler q个Ҏ(gu)只是通过toluafix_get_function_by_refid 获取到function然后通过lua_pcall Ҏ(gu)调用Q代码就不写了?/p>