Vhdl 在函数末尾返回值之前,如何取消分配acces类型变量?
在函数中,可以方便地使用Vhdl 在函数末尾返回值之前,如何取消分配acces类型变量?,vhdl,Vhdl,在函数中,可以方便地使用sting访问类型,例如通过文本行,最终值是函数的输出。显示问题的简单示例代码,但不是使用访问的动机类型: function fun return string is variable line_v : line; begin line_v := new string'("Hello VHDL world"); return line_v.all; -- line_v is missing deallocate(line_v) end function;
sting
访问
类型
,例如通过文本行
,最终值是函数的输出。显示问题的简单示例代码,但不是使用访问的动机
类型
:
function fun return string is
variable line_v : line;
begin
line_v := new string'("Hello VHDL world");
return line_v.all; -- line_v is missing deallocate(line_v)
end function;
但此代码缺少一个解除分配(第v行)
,以避免在未释放为字符串分配的内存时发生内存泄漏
当从
行v
返回值时,如何进行解除分配(行v)
?一种解决方案是返回访问类型而不是字符串:
library IEEE;
use std.textio.all;
function fun return line is
variable line_v : line;
begin
line_v := new string'("Hello VHDL world");
return line_v;
end function;
然后在函数外部取消分配:
library IEEE;
use std.textio.all;
entity E is
end entity E;
architecture E of E is
function fun return line is
variable line_v : line;
begin
line_v := new string'("Hello VHDL world");
return line_v;
end function;
begin
process
variable L : line := fun;
begin
report L.all;
deallocate(L);
wait;
end process;
end architecture E;
现在这真的很难看 首先创建一个受保护的类型:
package TextExtPkg is
type LinePType is protected
procedure copy ( S : in string ) ;
impure function get ( EraseLine : boolean := TRUE) return string ;
end protected LinePType ;
...
end TextExtPkg ;
package body TextExtPkg is
type LinePType is protected body
variable Message : line ;
procedure copy ( S : in string ) is
begin
deallocate(Message) ;
Message := new string'(S) ;
end procedure copy ;
impure function get ( EraseLine : boolean := TRUE) return string is
variable value : string(1 to Message'length) ;
begin
value := Message.all ;
if EraseLine then
deallocate(Message) ;
end if ;
return value ;
end function get ;
end protected body LinePType ;
end TextExtPkg ;
然后将该值放入受保护类型,取消分配本地指针,然后从受保护类型获取并返回该值。它不漂亮,但很管用
function fun return string is
variable line_v : line;
variable PT : LinePType ;
begin
line_v := new string'("Hello VHDL world");
PT.copy(line_v.all) ;
deallocate(line_v) ;
return PT.get(EraseLine => TRUE) ;
end function;
我用我的为整数向量创建了一个write and to_字符串(此处命名为to_s):
procedure write (
L : inout line;
value : in integer_vector;
justified : in side := RIGHT;
field : in width := 0
) is
begin
for i in value'range loop
write(L, value(i), justified, field) ;
if i /= value'right then
write(L, ' ') ; -- delimiter
end if ;
end loop ;
end procedure write ;
impure function to_s (
value : in integer_vector;
justified : in side := RIGHT;
field : in width := 0
) return string is
variable L : line;
variable PT : LinePType ;
begin
write(L, value, justified, field) ;
if L = NULL then return "" ; end if ;
PT.copy(L.all) ;
deallocate(L) ;
return PT.get(EraseLine => TRUE) ;
end function to_s ;
您可以在以下位置找到整个包:如何在C函数调用中执行此释放 VHDL不允许行内声明,这意味着取消分配函数中存储的唯一方法是返回一个动态声明的对象值。这将需要使用可保护的最大长度返回值:
entity noleak is
end entity;
architecture fum of noleak is
function fun (maxlen: natural := 16) return string is
use std.textio.all;
variable line_v : line;
variable retstr: string (1 to maxlen);
variable len: natural;
begin
line_v := new string'("Hello VHDL world!");
len := line_v.all'length;
if len <= maxlen then
retstr(1 to len) := line_v.all;
deallocate(line_v);
return retstr(1 to len);
end if;
deallocate(line_v);
return fun(maxlen => len);
end function;
begin
process
begin
report "fun return = " & fun(maxlen => 17);
report "fun return = " & fun;
wait;
end process;
end architecture;
保护被合并为动态细化的字符串数组的长度(它是一个堆栈变量)
如果Line access变量表示的字符串比该字符串数组变量长,则使用正确的长度递归调用函数。(注意该函数未被宣布为不纯。)
您可以根据您认为在一次过程中有效的内容选择maxlen默认值。如果你错了,它会通过递归来纠正
如果你知道这是错误的,你会通过一个更好的估计。解除分配由line\v line访问类型表示的对象需要首先将其值分配给一个动态细化的对象,以便在解除分配后用作返回值 这样做的困难来自这样一个要求,即动态声明的对象的声明在精化时必须是静态的,这意味着必须知道对象的子类型 在某些编程语言中,这可以通过使用行内声明来实现,其中一旦已知字符数组的长度,就可以将分配的内存区域的值复制到新声明的数组中 VHDL没有这种能力。但是,有一种方法可以通过嵌套函数调用来模拟它:
entity noleak is
end entity;
architecture fum of noleak is
impure function fun return string is
use std.textio.all;
variable line_v : line;
impure function snip return string is
variable retstr: string (1 to line_v'length);
begin
retstr := line_v.all;
deallocate (line_v);
return retstr;
end function;
begin
line_v := new string'("Hello VHDL world!");
return snip;
end function;
begin
process
begin
report "fun return = " & fun;
wait;
end process;
end architecture;
函数snip是不纯的,因为它修改了line_v access对象
函数乐趣是不纯的,因为它是不纯函数(snip)的父函数
函数snip被声明为包含一个返回字符串变量,该变量的长度取决于访问对象行_v指向的字符串值的长度值
之所以可以这样做,是因为子程序声明中的声明项可以是另一个子程序规范。这样做可以直接看到前面的声明(本例中为第五行)
第_v行访问的对象的长度用于动态细化的函数调用,以定义retstr的子类型(它的长度)
在snip的主体中,行_v访问的对象的值被复制到动态细化的retstr,行_v被释放。这表示将分配的对象(堆变量)转换为动态细化的对象(堆栈变量),然后释放分配的对象
这是VHDL中最接近于行内声明的地方
这里的想法是在不进行垃圾收集的VHDL实现中防止内存泄漏,如果访问类型值不是从函数返回的,或者不是过程的mode out或inout参数,则垃圾收集可能会在此处自动释放存储。在本例中,您根本不需要访问类型:初始化声明中的无约束字符串变量,并返回该变量。同意;我简化(删除)了实际的字符串操作,因此使用
访问类型的优势并不明显,但背景是中间和结果将是不同长度的字符串,对于这一点,访问类型字符串('line'))是一个很好的选择。有时您可以通过这种方式重新构造字符串操作;通过一系列函数调用,每个调用都使用上述函数,或者作为固定长度字符串的一部分。感谢您的建议,在某些情况下它可能会很有用。不过,避免用户函数清理并从函数中间删除是很好的。谢谢你的建议。所以基本上这个解决方案执行两次;第一个用于查找长度(如果guess太短),第二个用于生成字符串并返回它。如果line_v.all'length大于maxlen,则只执行两次。您可以提供任何默认值,如果它是maxlen或更短,它将执行一次传递。你也可以为maxlen oat分析时间使用不同的默认值,或者如果你期望更大的值,可以将其作为一个参数传递以扩大范围。是的,我同意你的观点。谢谢你的评论。谢谢吉姆。虽然解决方案需要更多的前期编写,但应用时保护类型(PT)的使用非常少,代码只执行一次,用户不会暴露于工件,因此解决方案封装了问题。我应该补充一点,在VHDL-2017中,将有更优雅的方法来解决这一问题。