I am working on a C-Ada binding application, where I am allocating a new string in Ada side using Interfaces.C.Strings.New_String()
.
我正在开发一个C-Ada绑定应用程序,在这个应用程序中,我使用Interfaces.C.Strings.New_String()在Ada端分配一个新的字符串。
Interfaces.C.Strings
already has a procedure Free()
to deallocate the memory for string. Since I need to pass this string to a C function using Interfaces.C.Strings.Chars_Ptr
:
Interfaces.C。string已经有一个Free()过程来释放字符串的内存。因为我需要使用Interfaces.C.Strings.Chars_Ptr将这个字符串传递给C函数:
-
Is it OK if I deallocate memory for the string in C side using the
free()
function (declared in stdlib.h)?如果我使用free()函数(在stdlib.h中声明)为C端中的字符串分配内存,可以吗?
-
Is it safe if I free the memory from C side?
如果从C端释放内存安全吗?
-
Or I should better free it using the
Interfaces.C.Strings.Free()
function from Ada side?或者我应该使用接口. c . strings . free()函数从Ada端释放它?
2 个解决方案
#1
4
There are two problems with calling Interfaces.C.Strings.Free
from the C side.
调用Interfaces.C.Strings有两个问题。不含C边。
The first is that the procedure has Convention Ada
, so you can’t be sure of how to call it from C, even if your compiler is GNAT & therefore GCC-based; and you can’t change this without editing and rebuilding the standard library.
第一个是过程有约定Ada,所以你不能确定如何从C调用它,即使你的编译器是基于GNAT &因此是基于gcc的;如果不编辑和重建标准库,就无法改变这一点。
The second is that its declaration is
第二,它的声明是
procedure Free (Item : in out chars_ptr);
which means that Item
is passed by reference (char **item
) so that it can be nulled.
这意味着该项是通过引用(char ** Item)传递的,因此可以将其无效。
You could arrange for the C side to call the Ada deallocation with wrapping. My view is that the Ada semantics (after Free (Item)
, Item
is set to Null_Ptr
) should be preserved, which means that the consuming C procedure to be called needs to take an in out
parameter, translated as char **
.
你可以安排C端调用Ada deallocation with wrap。我认为应该保留Ada语义(在Free (Item)之后,将Item设置为Null_Ptr),这意味着需要调用的消费C过程需要接受一个in out参数,翻译为char **。
with Interfaces.C.Strings;
package String_Freeing is
procedure C_Consumer (Item : in out Interfaces.C.Strings.chars_ptr)
with
Import,
Convention => C,
External_Name => "c_consumer";
procedure Free_Wrapper (Item : in out Interfaces.C.Strings.chars_ptr)
with
Export,
Convention => C,
External_Name => "free_ada_string";
end String_Freeing;
(Free_Wrapper
has to be in a package to be exported), with body
(Free_Wrapper必须在一个要导出的包中),它包含了body
package body String_Freeing is
procedure Free_Wrapper (Item : in out Interfaces.C.Strings.chars_ptr) is
begin
Interfaces.C.Strings.Free (Item);
end Free_Wrapper;
end String_Freeing;
and test program
和测试程序
with Interfaces.C.Strings;
with String_Freeing; use String_Freeing;
procedure Test_String_Freeing is
Str : Interfaces.C.Strings.chars_ptr;
use type Interfaces.C.Strings.chars_ptr;
begin
Str := Interfaces.C.Strings.New_String ("hello world.");
C_Consumer (Str);
pragma Assert (Str = Interfaces.C.Strings.Null_Ptr, "str not nulled");
end Test_String_Freeing;
where the C side of things might be
C在哪里
#include <stdio.h>
extern void free_ada_string(char **item);
void c_consumer(char **item) {
printf("%s\n", *item);
free_ada_string(item);
}
If you’re willing to leave dangling pointers on the Ada side, you could pass the string as an in
(char *
) parameter, which would make Free_Wrapper
look like
如果您愿意在Ada端留下悬浮指针,您可以将字符串作为in (char *)参数传递,这将使Free_Wrapper看起来像这样
package body String_Freeing is
procedure Free_Wrapper (Item : Interfaces.C.Strings.chars_ptr) is
Dummy : Interfaces.C.Strings.chars_ptr := Item;
begin
Interfaces.C.Strings.Free (Dummy);
end Free_Wrapper;
end String_Freeing;
(spec to be changed to match, of course).
(当然,要改为match)。
#2
5
You shall free this string on the Ada side:
你应该在Ada端释放这根绳子:
- the Ada API foresees this, so it's safe
- Ada API预见到了这一点,所以它是安全的
- the Ada API doesn't give any assurance that the memory is allocated using the C standard library (see package reference)
- Ada API不保证使用C标准库分配内存(参见包引用)
- you don't know if the internals of the Ada implementation that you use makes use of the standard C library, or if it has its own memory management. So it would be extremely risky to free it on the C side, because freeing a pointer that was not allocated with malloc/calloc is undefined behavior.
- 您不知道您使用的Ada实现的内部部分是否使用了标准C库,或者它是否有自己的内存管理。所以在C端释放它是非常危险的,因为释放一个没有分配给malloc/calloc的指针是没有定义的行为。
#1
4
There are two problems with calling Interfaces.C.Strings.Free
from the C side.
调用Interfaces.C.Strings有两个问题。不含C边。
The first is that the procedure has Convention Ada
, so you can’t be sure of how to call it from C, even if your compiler is GNAT & therefore GCC-based; and you can’t change this without editing and rebuilding the standard library.
第一个是过程有约定Ada,所以你不能确定如何从C调用它,即使你的编译器是基于GNAT &因此是基于gcc的;如果不编辑和重建标准库,就无法改变这一点。
The second is that its declaration is
第二,它的声明是
procedure Free (Item : in out chars_ptr);
which means that Item
is passed by reference (char **item
) so that it can be nulled.
这意味着该项是通过引用(char ** Item)传递的,因此可以将其无效。
You could arrange for the C side to call the Ada deallocation with wrapping. My view is that the Ada semantics (after Free (Item)
, Item
is set to Null_Ptr
) should be preserved, which means that the consuming C procedure to be called needs to take an in out
parameter, translated as char **
.
你可以安排C端调用Ada deallocation with wrap。我认为应该保留Ada语义(在Free (Item)之后,将Item设置为Null_Ptr),这意味着需要调用的消费C过程需要接受一个in out参数,翻译为char **。
with Interfaces.C.Strings;
package String_Freeing is
procedure C_Consumer (Item : in out Interfaces.C.Strings.chars_ptr)
with
Import,
Convention => C,
External_Name => "c_consumer";
procedure Free_Wrapper (Item : in out Interfaces.C.Strings.chars_ptr)
with
Export,
Convention => C,
External_Name => "free_ada_string";
end String_Freeing;
(Free_Wrapper
has to be in a package to be exported), with body
(Free_Wrapper必须在一个要导出的包中),它包含了body
package body String_Freeing is
procedure Free_Wrapper (Item : in out Interfaces.C.Strings.chars_ptr) is
begin
Interfaces.C.Strings.Free (Item);
end Free_Wrapper;
end String_Freeing;
and test program
和测试程序
with Interfaces.C.Strings;
with String_Freeing; use String_Freeing;
procedure Test_String_Freeing is
Str : Interfaces.C.Strings.chars_ptr;
use type Interfaces.C.Strings.chars_ptr;
begin
Str := Interfaces.C.Strings.New_String ("hello world.");
C_Consumer (Str);
pragma Assert (Str = Interfaces.C.Strings.Null_Ptr, "str not nulled");
end Test_String_Freeing;
where the C side of things might be
C在哪里
#include <stdio.h>
extern void free_ada_string(char **item);
void c_consumer(char **item) {
printf("%s\n", *item);
free_ada_string(item);
}
If you’re willing to leave dangling pointers on the Ada side, you could pass the string as an in
(char *
) parameter, which would make Free_Wrapper
look like
如果您愿意在Ada端留下悬浮指针,您可以将字符串作为in (char *)参数传递,这将使Free_Wrapper看起来像这样
package body String_Freeing is
procedure Free_Wrapper (Item : Interfaces.C.Strings.chars_ptr) is
Dummy : Interfaces.C.Strings.chars_ptr := Item;
begin
Interfaces.C.Strings.Free (Dummy);
end Free_Wrapper;
end String_Freeing;
(spec to be changed to match, of course).
(当然,要改为match)。
#2
5
You shall free this string on the Ada side:
你应该在Ada端释放这根绳子:
- the Ada API foresees this, so it's safe
- Ada API预见到了这一点,所以它是安全的
- the Ada API doesn't give any assurance that the memory is allocated using the C standard library (see package reference)
- Ada API不保证使用C标准库分配内存(参见包引用)
- you don't know if the internals of the Ada implementation that you use makes use of the standard C library, or if it has its own memory management. So it would be extremely risky to free it on the C side, because freeing a pointer that was not allocated with malloc/calloc is undefined behavior.
- 您不知道您使用的Ada实现的内部部分是否使用了标准C库,或者它是否有自己的内存管理。所以在C端释放它是非常危险的,因为释放一个没有分配给malloc/calloc的指针是没有定义的行为。