将String传递给C函数

时间:2015-04-10 12:34:59

标签: string ada

我正在寻找将字符串传递给C函数的不同方法。这是一个关于4种不同方式的示例,代码经过测试并且有效。

with Interfaces.C; use Interfaces.C;
with Interfaces.C.Strings; use Interfaces.C.Strings;
with System; use System;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure Main is

   procedure Strcpy (Target : out String; Source : in String) with Import, Convention => C, External_Name => "strcpy";
   procedure Strcpy (Target : Address; Source : Address) with Import, Convention => C, External_Name => "strcpy";
   procedure Strcpy (Target : out char_array; Source : in char_array) with Import, Convention => C, External_Name => "strcpy";
   procedure Strcpy (Target : chars_ptr; Source : chars_ptr) with Import, Convention => C, External_Name => "strcpy";

   Source        : String := "Duration: " & Character (nul);
   Target_String : String (Source'Range) := (others => ' ');
   Target_String_Address : String (Source'Range) := (others => ' ');
   Target_char_array : char_array (size_t (Source'First) .. size_t (Source'Last)) := (others => ' ');
   Target_chars_ptr : chars_ptr := New_Char_Array (Target_char_array);

   T : Time;
   D : Time_Span;
   N : constant := 100000000;
begin

   T := Clock;
   for I in 1..N loop
      Strcpy (Target_String, Source);
   end loop;
   D := Clock - T;
   Put_Line (Target_String & To_Duration(D)'Img);

   T := Clock;
   for I in 1..N loop
      Strcpy (Target_String_Address'Address, Source'Address);
   end loop;
   D := Clock - T;
   Put_Line (Target_String_Address & To_Duration(D)'Img);

   T := Clock;
   for I in 1..N loop
      Strcpy (Target_char_array, To_C (Source));
   end loop;
   D := Clock - T;
   Put_Line (To_Ada (Target_char_array) & To_Duration(D)'Img);

   T := Clock;
   for I in 1..N loop
      Strcpy (Target_chars_ptr, New_String (Source));
   end loop;
   D := Clock - T;
   Put_Line (Value (Target_chars_ptr) & To_Duration(D)'Img);

end;

测量

╔════════════╦════════════╦═════════════╗
║    Type    ║ Conversion ║ Duration[s] ║
╠════════════╬════════════╬═════════════╣
║ String     ║            ║ 0.564774366 ║
║ Address    ║            ║ 0.535110315 ║
║ char_array ║ To_C       ║ 2.938592901 ║
║ chars_ptr  ║ New_String ║ 6.790939748 ║
╚════════════╩════════════╩═════════════╝

考虑到良好的表现,我应该使用哪种方法?

传递String'Address将获得最佳性能,但我应该这样做吗?

任何Strcpy程序都有任何缺点吗?

任何Strcpy程序都有什么好处吗?

1 个答案:

答案 0 :(得分:3)

我不打算为你衡量表现。我希望你能够自己做到这一点。

您无法保证Standard.String个对象可以以始终有效的方式传递给任何C函数,因为Ada编译器不需要期望{{{{{{ 1}}别名。如果您确保Standard.String等同于Interfaces.C.char,那么类型为Standard.Character的对象已打包,并且类型为Standard.String的对象为空终止,那么我预计它可以在大多数情况下使用。

包装和等效是您必须通过实验检查作为自动构建和测试程序的一部分。

您可以使用Standard.String的子类型以及导入的C函数的形式参数的动态谓词来强制执行空终止:

Standard.String

如果你假设遵循LRM中的B.3(70)(技术上它只是实现建议,但我认为这是一个安全的假设),那么你可以直接在界面中使用with Ada.Characters.Latin_1; package Strings_For_C is NUL : constant Character := Ada.Characters.Latin_1.NUL; subtype C_String is Standard.String with Dynamic_Predicate => C_String'Length >= 1 and then C_String (C_String'Last) = NUL; end Strings_For_C; 导入的C程序代替C_String参数:

char*