2000行C++算法翻译成Lua历程与工具介绍

本文讲述了将高性能消耗的C++算法从服务器迁移到客户端以抵御恶意攻击的过程。通过C++到C#再到Lua的翻译工具,尽管减少了手动工作量,但面临Lua不支持的部分语法和性能下降的问题。作者对翻译后的代码进行优化,包括数组索引调整、内存拷贝的替代实现等,但也注意到C++位操作在Lua中的缺失和效率损失。整个过程揭示了跨语言代码迁移的复杂性和性能考量。

背景:某算法原本放在服务器运行,由玩家每请求一次运算一次,然而该算法性能消耗较大。若被第三方恶意攻击,此算法会急速消耗服务器CPU和内存,是较大的性能隐患,故需要迁移到客户端。

前排提醒,这篇文章是对代码文本的翻译,不是C++库的绑定。生产出来的代码依然需要手动修改部分,只是减少了大部分的工作量。

最开始接到这需求,我是手写翻译的,然而翻了几百行后,各种内存拷贝和指针跳转让我耐力耗尽,有些崩溃,而且手写翻译也不能保证手写代码的准确性。后面
花半天时间,到网上找了一些工具辅助这些代码的翻译。

首先,并没有在市面上找到靠谱C++直接翻译到Lua文本的工具。
最终选择的是一个折中方案,是用两个工具先将C++翻译到Csharp,然后再将Csharp翻译到Lua。
PS:市面上基本上都是Lua对C++的代码绑定,而不是直接的代码翻译。

补充:后续看到网上有同学说这个工具可以直接完成C++到Lua的翻译,感兴趣的可以尝试一下https://github.com/Oberon00/apollo

C++翻译到C#

C++翻译到C#,用的是工具**C++ to C# Converter破解版**,使用起来很简单。双击打开,选择源文件夹和目标文件夹就好了。
在这里插入图片描述
需要注意的是,我翻译的是服务器发给我的单个CPP文件,不是完整的C++工程,所以有很多字段引用不全,如果你跟我一样,那么你可能也会遇到以下几个问题。

  1. 提示导入某些系统库文件,可以选择“取消”,不会影响工具翻译,生成的代码中会注释掉这几行对系统库的引用。
    在这里插入图片描述
  2. 生成的C#的代码会有大量的报错,不过不必担心,这些一般都是引用丢失导致的(比如写在其他.h文件的声明,我们没有这个.h文件)。因为我们要翻译成Lua,一样引用不到这些丢失字段,可以直接注释掉。这些报错一般十分钟内可以搞定。Ps:必须把所有的错误解决掉,才能使用下一个C#转Lua的工具,所有报错都很好解决。
    全是报错

以下是我遇到编译错误列举

  • 引用丢失错误。这个数量太多没有截图
  • 默认数组的方法引用错误。在这里插入图片描述
  • 隐式转换错误
    在这里插入图片描述
  • 不支持指针赋值语法。在这里插入图片描述
  • 不支持内存拷贝方法。
  • 丢失命名空间和类型转换规则引起的错误
    在这里插入图片描述在这里插入图片描述
C#翻译到Lua

使用的是开源工具**CSharp.lua-1.6**(感谢这位开源大佬,好人平安https://github.com/yanghuan/CSharp.lua),工具需要donet环境支持。
微软官网下载最新版即可,安装简单,直接下一步下一步下一步,不赘述。https://dotnet.microsoft.com/download
在这里插入图片描述

下载好donet后,在CSharp.lua-1.6的目录下,按shift+右键,选择Powershell。输入如下命令

dotnet CSharp.lua/CSharp.lua.Launcher.dll -s [源文件夹完整地址,如:C:\Users\Administrator\Desktop\CPPTestConvert] -d [目标文件夹完整地址]

在这里插入图片描述
编译比较慢,耐心等待几秒钟,如果你的C#文件没有编译报错,将会看到成功提示。
在这里插入图片描述
如果你的C#依然有编译错误,将会提示你错误内容,。Ps:必须把所有的错误解决掉,才能C#转Lua的工具,所有报错都很好解决。
在这里插入图片描述
好了,到这里你就得到了,从C++到Lua的翻译代码,类似底下这种。
在这里插入图片描述

但是现在远没有结束。因为有些C++和C#的语法,Lua是不支持的,而且我翻译的是C++算法,对翻译过来的代码性能要求较高。
所以我又对代码进行了优化和整理。后面是优化和整理的内容。

  • 翻译过来的代码中包含大量的命名空间的使用,因为我的开发环境是Unity+Tolua,不确定能不能生效,我全部删掉了。
    在这里插入图片描述

  • 由于C++的数组索引从0开始,Lua是从1开始。调用时若不注意很容易出现异常。这里做了一个数组的中间版本,将传进来的Lua的数组索引改为0,以适配该算法。
    在这里插入图片描述

function GetZeroTagAutoAnalyseResult()
    local tagAutoAnalyseResult = CopyAllStruct(tagAutoAnalyseResult)
    for i = 0, ITEM_COUNT - 1 do
        tagAutoAnalyseResult.arrItem[i] = GetZeroTagCardItem()
    end
    return tagAutoAnalyseResult
end

function CreateNumberArray(tartgetLength)
    local listArray = {}
    for i = 0, tartgetLength - 1 do
        listArray[i] = 0
    end
    return listArray
end
function CreateNumberArrayArray(tartgetLength1, tartgetLength2)
    local listArray = {}
    for i = 0, tartgetLength1 - 1 do
        listArray[i] = CreateNumberArray(tartgetLength2)
    end
    return listArray
end
function CreateAndInitNumberArray(...)
    local param = {...}
    local listArray = {}
    for i = 0, #param - 1 do
        listArray[i] = param[i + 1]
    end
    return listArray
end

function CopyPartlyArray(tartgetArray, resArray, length, offset)
    offset = offset or 0
    for i = 0, length - 1 do
        tartgetArray[i + offset] = resArray[i]
    end
end

function ClearNumberArray(listArray)
    for i, v in ipairs(listArray) do
        listArray[i] = 0
    end
end
  • C++算法中常用的内存拷贝操作,Lua是不支持的,做了个Lua版本,可惜效率跟C++的内存操作相比会慢很多。
function CopyAllStruct(resStruct)
    local copy = {}
    for k, v in pairs(resStruct) do
        if type(v) == "table" then
            v = CopyAllStruct(v)
        end
        copy[k] = v
    end
    return copy
end
  • 服务器为了提高算法性能,算法中用了很多按位操作,Lua是没有原生支持的,网上的bit库效率十分低,这些逻辑只能删掉重写。这要看具体的业务逻辑了,没办法分享。

  • 还有个我犯得严重错误,不熟悉指针的赋值机制,导致直接使用=,代替了指针的赋值。因为我这次翻译的算法代码比较多,这一个小细节,服务器协助我查了一上午才找到原因。
    -- AnalyseResult = pResult --AnalyseResult = *pResult; AnalyseResult = CopyAllStruct(pResult)

总结

到这里,所有的翻译就完成了,虽然还是有不少的代码要修改,但是总体来说减少了大量的开发时间,特别是后期因手写造成的错误的调试和测试时间。

不过除非像我这种特殊需求,尽量还是不要将C++翻译到Lua吧,实际翻译之后该算法相比在服务器,运行效率降低了一百倍左右。

这个C++管理系统基本涵盖了“学生成绩管理系统”的所有功能,你可以从中借鉴到C++链表、类、封装、继承、文件操作、排序等等很多知识,极具借鉴意义,以下为本项目的功能介绍: 1. 建立文件 (1)可以使用默认文件名或指定文件名将记录存储到 (2)设置适当的标志位,作为对记录进操作的 (3)写同名文件将覆盖原来文件的 2.增加学生记录 (1) 可在已有记录后面追加新的记录 (2) 可以随时增加新的记录,它们仅保存在向量数组中 (3) 可以将一个文件读入,追加在已有记录之后 (4) 采取文件追加方式时,在没有保存到文件之前,将继续保持文件追加状态,以便实现连续追加操作方式 3. 新建学生信息文件 (1) 用来新建学生信息记录 (2) 如果已经有记录存在,可以覆盖原记录或者在原记录后面追加,也可以将原有记录信息保存 到一个指定文件,然后重新建立记录 (3) 给出相应的提示信息 4. 显示记录 (1) 如果没有记录可供显示,给出提示信息 (2) 可以随时显示内存中的记录 (3) 显示表头 5. 文件存储 (1) 可以按默认名字或指定名字存储记录文件 6. 读取文件 (1) 可以按默认名字或指定名字将记录文件读入内存 (2) 可以将指定或默认文件追加到现有记录的尾部 (3) 可以将文件连续追加到现有记录并更新记录中的“名次” 7. 删除记录 (1) 可以按“学号”、“姓名”或“名次”方式删除记录 (2) 标志将被删除的记录, 可以再次取消标志, 经确认后删除已经标志的记录(3) 如果记录是空表, 删除时应给出提示信息并返回主菜单 (4) 如果没有要删除的信息, 输出“没有找到”的信息 (5) 更新其他记录的名次 (6) 删除操作仅限于内存, 只有执存储操作时, 才能覆盖原记录 8. 修改记录 (1) 可以按“学号”、“姓名”或“名次”方式查找要修改的记录内容 (2) 给出将被修改记录的信息, 经确认后进修改 (3) 如果记录已经是空表,应给出提示信息并返回主菜单 (4) 如果没有找到需要修改的信息, 输出“没有找到”的信息 (5) 更新其他记录的名次 (6) 修改操作仅限于内存, 只有执存储操作时, 才能覆盖原记录 9. 查询记录 (1) 可以按“学号”、“姓名”或“名次”方式查询记录 (2) 能给出查询记录的信息 (3) 如果查询的信息不存在, 输出提示信息 10. 对记录进排序 (1) 可以按”学号”进升序和降序排列 (2) 可以按”姓名”进升序和降序排列 (3) 可以按”名次”进升序和降序排列 (4) 如果属于选择错误, 可以立即退出程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值