使用 free() 在 C 函数中释放字符串(在 Ada 中分配)
Freeing a string (allocated in Ada) in a C function using free()
我正在开发一个 C-Ada 绑定应用程序,我正在使用 Interfaces.C.Strings.New_String()
在 Ada 端分配一个新字符串。
Interfaces.C.Strings
已经有一个过程 Free()
来释放字符串的内存。因为我需要使用 Interfaces.C.Strings.Chars_Ptr
将此字符串传递给 C 函数:
如果我在C端使用free()
函数(在stdlib.h中声明)为字符串释放内存可以吗?
从C端释放内存安全吗?
或者我最好使用 Ada 端的 Interfaces.C.Strings.Free()
函数释放它?
您应在 Ada 端释放此字符串:
- 艾达 API 预见到了这一点,所以它是安全的
- Ada API 不保证内存是使用 C 标准库分配的(参见 package reference)
- 您不知道您使用的 Ada 实现的内部结构是否使用了标准 C 库,或者它是否有自己的内存管理。所以在 C 端释放它是非常危险的,因为释放一个没有用 malloc/calloc 分配的指针是未定义的行为。
从C端调用Interfaces.C.Strings.Free
有两个问题
首先是该过程具有 Convention Ada
,因此您无法确定如何从 C 调用它,即使您的编译器是 GNAT 并且因此是基于 GCC 的;如果不编辑和重建标准库就无法更改它。
第二个是它的声明是
procedure Free (Item : in out chars_ptr);
这意味着 Item
通过引用传递 (char **item
) 以便它可以为空。
您可以安排C 端调用带包装的Ada 释放。我的观点是应该保留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
必须在要导出的包中), with 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;
和测试程序
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;
C 端可能在哪里
#include <stdio.h>
extern void free_ada_string(char **item);
void c_consumer(char **item) {
printf("%s\n", *item);
free_ada_string(item);
}
如果您愿意在 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;
(当然要更改规格以匹配)。
我正在开发一个 C-Ada 绑定应用程序,我正在使用 Interfaces.C.Strings.New_String()
在 Ada 端分配一个新字符串。
Interfaces.C.Strings
已经有一个过程 Free()
来释放字符串的内存。因为我需要使用 Interfaces.C.Strings.Chars_Ptr
将此字符串传递给 C 函数:
如果我在C端使用
free()
函数(在stdlib.h中声明)为字符串释放内存可以吗?从C端释放内存安全吗?
或者我最好使用 Ada 端的
Interfaces.C.Strings.Free()
函数释放它?
您应在 Ada 端释放此字符串:
- 艾达 API 预见到了这一点,所以它是安全的
- Ada API 不保证内存是使用 C 标准库分配的(参见 package reference)
- 您不知道您使用的 Ada 实现的内部结构是否使用了标准 C 库,或者它是否有自己的内存管理。所以在 C 端释放它是非常危险的,因为释放一个没有用 malloc/calloc 分配的指针是未定义的行为。
从C端调用Interfaces.C.Strings.Free
有两个问题
首先是该过程具有 Convention Ada
,因此您无法确定如何从 C 调用它,即使您的编译器是 GNAT 并且因此是基于 GCC 的;如果不编辑和重建标准库就无法更改它。
第二个是它的声明是
procedure Free (Item : in out chars_ptr);
这意味着 Item
通过引用传递 (char **item
) 以便它可以为空。
您可以安排C 端调用带包装的Ada 释放。我的观点是应该保留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
必须在要导出的包中), with 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;
和测试程序
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;
C 端可能在哪里
#include <stdio.h>
extern void free_ada_string(char **item);
void c_consumer(char **item) {
printf("%s\n", *item);
free_ada_string(item);
}
如果您愿意在 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;
(当然要更改规格以匹配)。