代码之家  ›  专栏  ›  技术社区  ›  yCalleecharan

Ada软件工程:stubs;独立编制单位[关闭]

  •  3
  • yCalleecharan  · 技术社区  · 16 年前

    我有机械工程背景,但我有兴趣学习与Ada良好的软件工程实践。我有几个问题。

    问题2。我的第二个问题是关于存根(子单元)和使用独立的。假设我有一个主程序如下:

        WITH Ada.Float_Text_IO;
        WITH Ada.Text_IO;
        WITH Ada.Integer_Text_IO;
    
        PROCEDURE TEST2 IS
        A,B      : FLOAT;
        N        : INTEGER;
    
        PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS SEPARATE;
    
        BEGIN -- main program
          INPUT(A,B,N);
          Ada.Float_Text_IO.Put(Item => A);
          Ada.Text_IO.New_line;
          Ada.Integer_Text_IO.Put(Item => N);
        END TEST2;
    

    separate(TEST2)
    PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
       BEGIN
          Ada.Float_Text_IO.Get(Item => A);
          Ada.Text_IO.New_line;
          Ada.Float_Text_IO.Get(Item => B);
          Ada.Text_IO.New_line;
          Ada.Integer_Text_IO.Get(Item => N);
       END INPUT;
    

    我的问题:

    a) AdaGIDE建议我将输入过程文件保存为INPUT.adb。但是在编译主程序test2时,我得到了警告:

    warning: subunit "TEST2.INPUT" in file "test2-input.adb" not found
    cannot generate code for file test2.adb (missing subunits)
    

    对AdaGIDE来说,这更像是一个错误,因为上述警告出现在消息之前:

    Compiling...
    Done--error detected
    

    因此,我将input.adb文件重命名为test2-input.adb,正如AdaGIDE在编译时向我建议的那样。现在编译主文件,我没有任何警告。我现在的问题是是否可以写

    PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
    

    就像我在子单元文件test2-input.adb中所做的那样,还是编写一个更具描述性的术语,比如

    PROCEDURE TEST2-INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
    

    强调过程输入有一个父过程test2?这个想法来自于AdaGIDE向我暗示test2-input.adb,正如我前面提到的那样。

    如果我很好地理解编译顺序,那么我应该先编译主文件test2.adb,然后编译存根test2-input.adb。编译存根时,我收到错误消息:

    cannot generate code for file test2-input.adb (subunit)
    Done--error detected
    

    不过,我现在可以为test2.adb进行绑定和链接并运行程序。

    我想知道我是否在尝试编译stub test2-input.adb时出错了,还是不应该编译它?

    问题3。有亚单位有什么用?只是为了把一个大程序分解成更小的部分?我知道如果在子单元的BEGIN和END之间没有任何语句,就会出现错误。所以这意味着一个人总是要把一个陈述放在那里。如果要稍后编写语句,可以始终在子单元的BEGIN和END之间放置一个NULL语句,并在稍后返回到后者。软件工程在实践中就是这样做的吗?

    谢谢。。。

    3 回复  |  直到 13 年前
        1
  •  7
  •   Marc C    16 年前

    问题1:就是这样 杰出的 练习。

    将包装规格视为 规范 ,您可以将其提供给其他开发人员,以便他们知道如何与您的代码进行接口。

    问题2:我认为AdaGIDE实际上使用GNAT编译器进行所有编译,所以实际上是GNAT负责可接受的文件名(这是可以配置的,但是除非你有一个非常有说服力的理由这样做,否则简单地使用GNAT/AdaGIDE的文件命名约定要简单得多。)不过,与你的问题更相关的是,没有充分的理由将父单元作为单独单元名称的一部分。但是看看第三个问题的答案。。。

    问题3:Ada的第一个版本ADA83引入了子单元,部分是为了帮助模块化代码,并允许延迟开发和编译。然而,Ada软件开发实践几乎放弃了子单元的使用,所有的过程/函数/任务/etc体都简单地保存在包体中。它们仍在某些领域使用,比如可能需要特定于平台的子程序版本,但大多数情况下很少使用。它留下更少的文件来跟踪,并将包的实现代码放在一起。因此,我强烈建议您忽略子单元功能,将所有实现代码放在包体中。

        2
  •  4
  •   Simon Wright    16 年前

    将问题分解为组件(包)是很正常的,每个组件(包)支持不同的方面。如果你已经学会了Ada,那么首先编写软件包的规格说明是很正常的,然后讨论(也许和你自己)为什么这是正确的设计,然后实现它们。我认为,这在任何支持规范和实体的语言中都是正常的,例如,C。

    就我个人而言,我会边走边检查汇编,以确保我没有做任何蠢事。

    至于分离-一个(不是很好)的原因是减少混乱,以防止单位太长。另一个原因(对于我编写的代码生成器)是代码生成器不需要担心在UML模型中保留开发人员手工编写的代码;所有代码体都是分开的。第三种可能是与环境相关的实现(例如,Windows vs Unix),您可以让编译器看到每个环境的独立主体的不同版本(不过,人们通常使用库包)。

    procedure Foo is
       procedure Bar is separate;
    

    它希望在一个名为 foo.adb 酒吧的尸体在里面 foo-bar.adb )我相信,你可以说得不同- gnatmake 的包 Naming -但这可能不值得麻烦)。这里最好顺其自然;

    separate (Foo)
    procedure Bar is
    

    已经够清楚了。

    foo-bar.adb文件 ,这将进行全面的分析并捕获代码中几乎所有的错误;但是GNAT不能自己生成代码。相反,当您编译 亚洲开发银行 它在一个生成的对象文件中包含所有单独的实体。当然不是 做这个。

    啃食 让电脑承受压力!

        3
  •  1
  •   T.E.D.    16 年前

    您确实可以按照您描述的方式工作,当然,除非在所有包体都有某种实现之前,您的程序不会链接。因此,我认为更正常的做法是编写一个虚拟包体,其中所有过程都实现为:

    begin
       null;
    end;
    

    所有功能的实现方式如下:

    begin
       return The_Return_Type'first; --'
    end;
    

    巨大的 但在这种情况下,更好的解决方案几乎总是重构代码。所以每当我看到一个,它是一个大红旗。

    至于文件名问题,这是一个gnat问题,而不是Ada问题。Gnat对编译器采取了一种不同寻常的立场,即文件内容的名称决定了文件本身的名称。世界上可能还有其他编译器可以做到这一点,但我在30年的编码生涯中还没有找到一个。