我们使用的静态分析器的报告显示:
带有本地子程序(OPTI7)的子程序
本节列出了本身具有本地子程序的子程序。特别是当这些子程序共享局部变量时,可能会对性能产生负面影响。
本指南说:
请勿使用嵌套例程嵌套例程(其他例程中的例程;也称为“本地过程”)需要某些特殊的堆栈操作,以便内部例程可以看到外部例程的变量。这导致大量开销。而不是嵌套,将过程移至单位作用域级别并传递必要的变量(如果需要,可以通过引用(使用var关键字)进行传递),或者使变量在单位范围内变为全局。
我们很想知道在验证我们的代码时是否应考虑此报告。这个问题的答案表明,应该对自己的应用程序进行概要分析以查看是否存在性能差异,但是对于嵌套例程和普通子例程之间的差异却没有多说。
嵌套例程和普通例程之间的实际区别是什么?它会导致性能下降吗?
在Delphi中,string <> ''似乎生成的代码少于Length(string) > 0.
比较空字符串,定义TMyClass.UpdateString(const strMyString : String)如下:
MyClassU.pas.31: begin
005CE6A0 55 push ebp
005CE6A1 8BEC mov ebp,esp
005CE6A3 83C4F8 add esp,-$08
005CE6A6 8955F8 mov [ebp-$08],edx
005CE6A9 8945FC mov [ebp-$04],eax
MyClassU.pas.32: if (strMyString <> '') then
005CE6AC 837DF800 cmp dword ptr [ebp-$08],$00
005CE6B0 740E jz $005ce6c0
Run Code Online (Sandbox Code Playgroud)
据我了解,这是将动态分配的字符串([ebp-$08])的地址与零进行比较.有道理,因为空字符串指向nil.
比较长度,定义TMyClass.UpdateString2(const strMyString : String)如下:
MyClassU.pas.25: begin
005CE664 55 push ebp
005CE665 8BEC mov ebp,esp
005CE667 83C4F4 add esp,-$0c
005CE66A …Run Code Online (Sandbox Code Playgroud) 考虑下面的代码,这是一种基于当前时间生成整数标识符的简单方法,其中ResultInt64:
dtRef := Now;
Result := YearOf(dtRef) * 100000000000 +
MonthOf(dtRef) * 1000000000 +
DayOf(dtRef) * 10000000 +
HourOf(dtRef) * 100000 +
MinuteOf(dtRef) * 1000 +
SecondOf(dtRef) * 10 +
m_nLastTaskID;
Run Code Online (Sandbox Code Playgroud)
例如,今天生成的ID给出了20190503163412142(<2 ^ 55),这恰好在Int64(2 ^ 63-1)的范围内。
但是,这在柏林和里约都有整数溢出。它编译为:
MyUnitU.pas.580: Result := YearOf(dtRef) * 100000000000 +
007BCEAE 6A17 push $17
007BCEB0 6800E87648 push $4876e800
007BCEB5 FF75EC push dword ptr [ebp-$14]
007BCEB8 FF75E8 push dword ptr [ebp-$18]
007BCEBB E84CF2D3FF call YearOf
007BCEC0 0FB7C0 movzx eax,ax
007BCEC3 33D2 xor edx,edx
007BCEC5 E8FA0AC5FF …Run Code Online (Sandbox Code Playgroud) 我只是为了易读性而声明了一些函数,我想检查编译器是否在内联它们.根据这个答案,我想我可以标记它们inline并获得一个提示,如果它们没有内联,但是,当我尝试这样做时,我得到以下错误:
[dcc32 Error] MyClass.pas(266): E1030 Invalid compiler directive: 'INLINE'
Run Code Online (Sandbox Code Playgroud)
所以我尝试了一个简单的功能:
procedure TMyClass.Swap(var a, b : Integer); inline;
var
c : Integer;
begin
c := a;
a := b;
b := c;
end;
Run Code Online (Sandbox Code Playgroud)
唉,我得到了同样的错误.根据默认的文档{$INLINE ON},所以我假设我只需添加inline;.尽管如此,我试图宣布{$INLINE ON},但无济于事.我的Google-fu让我失望了,所以我在这里.
我正在使用Delphi 10.1 Berlin.
我有一个.groupproj文件,我用它来自动构建几个项目,通过构建组项目.我还增加了主要版本,并Project > Options > Version Info在Delphi的IDE(RAD Studio,10.1柏林)中添加了一个新的FileDescription ,但必须手动为每个项目完成.由于新版本经常发布,因此这个手动过程变得很麻烦.是否有任何方法可以自动为组中的每个项目执行此操作?也就是说,假设新版本和文件描述对于组中的每个项目都是相同的.
我写了一个bash脚本来执行此操作,但它似乎不起作用.当在寻找... > Version Info它看起来是正确的IDE,但在那产生,在可执行文件的属性看时Details,当使用脚本,但正确的,当手动完成文件版本和文件的描述是不正确的.这很重要,因为另一个软件使用此信息.
我也尝试过在脚本中找到的正则表达式模式的变体,但无济于事.
我找不到.proj自动和手动生成的版本中的其他元数据文件与解释问题之间的任何显着差异.我无法提供它们,因为我不拥有此项目代码的权利.
除了使用宏录制器和剪贴板管理器之外,还有更好的方法吗?
在C我使用转到链条在错误释放资源,建议在这里.使用Delphi我遇到了以下情况,我想优雅地处理内存耗尽并防止内存泄漏:
New(A);
A.DoSomething;
New(A.B);
A.B.DoSomething;
New(A.C);
A.C.DoSomething;
Run Code Online (Sandbox Code Playgroud)
据我所知,检查内存耗尽的方法是捕获由异常引发的异常New.假设DoSomething所有函数都抛出Exception错误.SEI CERT的编码标准建议不要使用带内错误检查,也不要使用控制流的异常,至少对于Java来说,我认为这是非常合理的.我不确定如何处理这种情况,牢记这些建议.我的想法是做一些类似的事情
function AllocStuff : TA;
begin
New(Result);
Result.B := nil;
Result.C := nil;
Result.DoSomething;
New(Result.B);
Result.B.DoSomething;
New(Result.C);
Result.C.DoSomething;
end;
Run Code Online (Sandbox Code Playgroud)
捕获调用者的异常:
procedure QuestionableControlFlow;
var
A : TA;
begin
A := nil;
try
A := AllocStuff;
DoSomethingWith(A);
Dispose(A);
except on E : Exception do
begin
if (A <> nil) then
begin
if (A.B <> nil) then
begin
if (A.C <> nil) then …Run Code Online (Sandbox Code Playgroud)