例如:
type PERSONCV is record name: String ( 1..4 ); age: Integer; cvtext: String ( 1..2000 ); end record; N: constant := 40000; persons : array ( 1..N ) of PERSONCV; function jobcandidate return Boolean is iscandidate: Boolean := False; begin for p of persons loop -- what code is generated for this? if p.age >= 18 then iscandidate := true; exit; end if; end loop; return iscandidate; end;
在C/C++中,循环部分通常是:
PERSONCV * p; // address pointer int k = 0; while ( k < N ) { p = &persons [ k ]; // pointer to k'th record if ( p->age >= 18 )... ... k++ ; }
我读过Ada对记录使用Value语义.上面的Ada循环是否将第k个记录复制到循环变量p?例如,这是在C/C++中:
PERSONCV p; // object/variable int k = 0; while ( k < N ) { memcpy ( &p, &persons [ k ], sizeof ( PERSONCV ) ); // copies k'th elem if ( p.age >= 18 )... ... k++ ; }
Simon Wright.. 13
假设您使用的是GNAT,则有两种调查途径.
交换机-gnatG
将重新生成类似Ada的表示,表示编译器的前端将传递到后端(在任何优化之前).在这种情况下,我明白了
function resander__jobcandidate return boolean is iscandidate : boolean := false; L_1 : label begin L_1 : for C8b in 1 .. 40000 loop p : resander__personcv renames resander__persons (C8b); if p.age >= 18 then iscandidate := true; exit; end if; end loop L_1; return iscandidate; end resander__jobcandidate;
所以问题是,如何renames
翻译?鉴于记录大小是2008字节,编译器生成副本的几率几乎为零.
第二种调查方法是保留编译器通常发送给汇编器的汇编代码,然后使用该开关删除-S
.这证实生成的代码就像您的第一个C++版本(对于macOS).
作为一个有趣的侧面,Ada 2012允许替代实施jobcandidate
:
function jobcandidate2 return Boolean is (for some p of persons => p.age >= 18);
它生成相同的代码.
假设您使用的是GNAT,则有两种调查途径.
交换机-gnatG
将重新生成类似Ada的表示,表示编译器的前端将传递到后端(在任何优化之前).在这种情况下,我明白了
function resander__jobcandidate return boolean is iscandidate : boolean := false; L_1 : label begin L_1 : for C8b in 1 .. 40000 loop p : resander__personcv renames resander__persons (C8b); if p.age >= 18 then iscandidate := true; exit; end if; end loop L_1; return iscandidate; end resander__jobcandidate;
所以问题是,如何renames
翻译?鉴于记录大小是2008字节,编译器生成副本的几率几乎为零.
第二种调查方法是保留编译器通常发送给汇编器的汇编代码,然后使用该开关删除-S
.这证实生成的代码就像您的第一个C++版本(对于macOS).
作为一个有趣的侧面,Ada 2012允许替代实施jobcandidate
:
function jobcandidate2 return Boolean is (for some p of persons => p.age >= 18);
它生成相同的代码.
我怀疑你读到的有关Ada的内容是错误的,而且可能更糟糕的是,鼓励你以错误的方式思考Ada.
Ada的目的是鼓励在问题领域进行思考,即指定应该发生什么,而不是在解决方案领域进行思考,即实现精确的细节.
所以这里的目的是遍历所有人,在第一次超过18时退出返回True,否则返回False.
就是这样.
一般来说,只要这些语义得到满足,Ada就不会详细说明它是如何完成的.
然后,意图是,你只希望编译器做正确的事情.
现在,单个编译器可以选择一个实现而不是另一个 - 或者可以根据优化启发式在实现之间切换,考虑它正在编译的CPU,以及对象的大小(它们是否适合寄存器?)等.
您可以想象一个具有许多寄存器的CPU,其中单个高速缓存行读取使得复制实现比在适当位置操作更快(特别是如果没有修改以回写到P的内容),或者反向为真的其他目标CPU.为什么要阻止编译器选择更好的实现?
这方面的一个很好的例子是艾达对参数传递到子程序的做法-名称,值或引用传递真的不适用-相反,您指定的参数传递模式- in
,out
或in out
描述信息流(或)子程序.直观,提供可以更严格检查的语义,并使编译器可以自由选择正确遵循这些语义的最佳(最快,最小,取决于您的目标)实现.
现在,特定的Ada编译器可能会做出糟糕的选择,而30年前,当计算机根本不足以运行Ada编译器时,您可能会发现在编译器的早期版本中,为了简单起见,性能受到了损害.
但是我们现在有三十多年的编译器开发,在更强大的计算机上运行.所以,今天,我希望编译器能够正常地做出最佳选择.如果您发现某个特定编译器错过了性能优化,请提交增强请求.Ada编译器并不完美,就像任何其他编译器一样.
在这个具体的例子中,我通常希望P成为数组的游标,并且操作就地发生,即引用语义.或者可能是表单之间的混合,其中一个存储器提取到寄存器中用于多个操作,如部分形式的值语义.
如果您的兴趣是学术性的,您可以轻松查看您正在使用的任何编译器的汇编输出并找出答案.或者写上面的所有三个版本并对它们进