何时使用Pragma Pure/Preelaborate

Ant*_*ony 18 ada pragma elaboration

有一组通用规则/指南,可以帮助了解什么时候喜欢pragma Pure,pragma Preelaborate或别的东西完全?标准(Ada 2012)中提出的规则和定义有点沉重,我很感激阅读一些更为清晰的内容并针对普通案例.

如果我想彻底了解它的"原因",我可以简单地试试:

  • 标记包规格 pragma Pure;
  • 如果没有编译,请尝试 pragma Preelaborate;
  • 如果失败了,那么我已经做了一些棘手的事情,要么需要逐个pragma Elaborate单元,要么重新考虑包布局.withwith

虽然这可能有效(是吗?),因为建议尽可能将包标记为Pure(同样使用Preelaborate),但它看起来有点脑损伤,我更愿意更好地理解这个过程.

fly*_*lyx 19

pragma Pure

您应该在没有内部状态的任何包上使用它.它告诉用户包调用任何子程序不能有副作用,因为没有内部状态可以改变.因此,在使用相同参数调用时,在纯包内的库级声明的函数将始终返回相同的结果.

允许Ada实现缓存纯包的函数的返回值,并且如果由于这些要求而不使用它们的返回值,则省略对子例程的调用.但是,您可以通过调用纯包中的导入子例程(例如,从C库)来违反约束(这些可能会更改Ada编译器不知道的某些内部状态).如果你是邪恶的,你甚至可以从软件的其他部分导入Ada子程序,pragma Import以绕过要求pragma Pure.毋庸置疑:如果您正在做这样的事情,请不要使用pragma Pure.

编辑:为了澄清可能省略调用的情况,让我引用ARM:

如果库单元被声明为纯,那么如果在调用之后不需要结果,则允许实现省略对库单元的库级子程序的调用.类似地,它可以省略这样的调用并简单地重用先前调用在同一子程序上产生的结果,前提是没有任何参数是有限类型的,并且所有参考实际参数的地址和值,以及所有by-copy-in实际参数的值与之前调用时的值相同.即使子程序在调用时产生其他副作用,此权限也适用.

例如,GNAT还定义了任何System.Address带有类型参数或从中派生的类型的子例程都不被认为是纯粹的,即使它们是在纯包中定义的,因为地址指向的位置可能会被改变,但是GNAT确实如此.不知道地址指向哪种结构,因此无法检查参数的引用值是否已更改.

pragma Preelaborate

这告诉编译器程序包将不会在精化时(即主程序开始执行之前)执行任何代码.在详细说明时,将执行以下构造:

  • 库级变量的初始化(这可以是一个函数调用)
  • 在库级声明的任务的初始化(它们可能在主程序之前开始执行)
  • begin ... end图书馆一级街区的陈述

如果您不需要这些东西,通常应该避免这些.pragma Preelaborate尽可能使用,它告诉调用者他可以安全地使用包,而无需在精心设计时执行任何操作.

如果在你认为应该使用其中一个pragma时没有编译某些内容,请查看它为什么不编译.它可以帮助您发现包实现或结构的问题.不要在编译时删除pragma.由于约束会影响依赖于您的任何包的可能约束,因此您应始终选择最严格的适用pragma.


tra*_*god 5

GNAT 中的细化订单处理是一个有用的指南。理想情况下,标准规则足以满足大多数程序。编译指示告诉编译器替换您的详细说明顺序。它们应该应用于解决具体问题,而不是凭经验使用。

附录:@ajb 强调了编译指示之间的重要区别。引用的文章同意问题中概述的方法(第一点和第二点):“因此,一个好的规则是将单位标记为或Pure如果Preelaborate可能,如果不可能,则将它们标记为Elaborate_Body如果可能。” 它继续讨论“这三个编译指示都不能使用”的情况(第三点)。

  • @trashgod,我不得不避免将我的问题表述为“你能详细说明一下吗?” (2认同)