在软件工程领域,有一句著名的话,叫做“Don't Reinvent the Wheel”-----不要重复发明轮子。究其原因一方面是重复发明效率低下,另一方面是重新发明的轮子未必好用,也许发明之后发现轴承有问题,或者是有着各种瑕疵…….对于编程来说,“复用代码”有着更明确的好处。因此,如果有可能,我们希望更多秉承鲁迅先生提出的“拿来主义”在代码设计上。最近研究了一些C语言的库,得益于UEFI 的设计和 CLIB 的支持,大部分库都可以直接使用。今天介绍的是一个可以用于表达式计算的库:TinyExpr【参考1】。
首先是要将 TinyExpr Porting 到UEFI上,直接编译会出现一些 Error 和 Warning。经过研究,需要在 INF中加入下面的内容:
1.引入LibMath,否则一些 cos 之类的函数无法识别
[LibraryClasses] ShellCEntryLib UefiLib LibC LibStdio LibMath
2.关闭一些 Warning
[BuildOptions] MSFT:*_*_IA32_CC_FLAGS = /Ze /wd4201 /wd4152 /wd4090 /wd4204 /wd4055 /wd4244 MSFT:*_*_X64_CC_FLAGS = /Ze /wd4201 /wd4152 /wd4090 /wd4204 /wd4055 /wd4244
其中 C4201 Warning【参考2】,是 VS 编译器的扩展特性,比如下面这样的定义,在正经的 C 中是不允许的,但是 VC 中做了扩展是可以的:
struct S { float y; struct { int a, b, c; // C4201 }; } z;
这样扩展之后,可以直接使用 z.a 和 z.b。
此外,tinyexpr.c 中有关于 NAN 的定义和StdLib中的 Math.h中的存在冲突。我的解决方法是先用 #undef NAN 取消之前的定义,再根据 VS 编译器中 Math.h 的定义重写一次,结果如下:
//#ifndef NAN //#define NAN (0.0/0.0) #undef NAN #define NAN ((float)(INFINITY * 0.0F)) //#endif 最终测试代码如下: #include <Library/BaseLib.h> #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/PrintLib.h> #include <Library/ShellCEntryLib.h> #include <Protocol/EfiShell.h> #include <Library/ShellLib.h> #include <stdio.h> #include <math.h> #include "tinyexpr.h" /** Set the socket options @param [in] Argc The number of arguments @param [in] Argv The argument value array @retval 0 The application exited normally. @retval Other An error occurred. **/ int main ( IN int Argc, IN char **Argv ) { const char *c = "sqrt(5^2+7^2+11^2+(8-2)^2)"; double r = te_interp(c, 0); printf("The expression:\n\t%s\nevaluates to:\n\t%f\n", c, r); return 0; }
上述代码计算表达式
结果如下:
完整的代码下载:
expr
参考:
1.https://github.com/codeplea/tinyexpr
2.https://msdn.microsoft.com/en-us/library/c89bw853.aspx