string - 将字符串传递给 C 函数

标签 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 过程有什么好处吗?

最佳答案

我不会为您衡量绩效。我希望您能够自己做到这一点。

您无法保证 Standard.String 对象能够以始终有效的方式传递给任何 C 函数,因为 Ada 编译器不需要期望单个对象Standard.String 中要设置别名的字符。如果您确保 Interfaces.C.char 等同于 Standard.Character,则 Standard.String 类型的对象已打包,并且您的 Standard.String 类型的对象以 null 结尾,那么我希望它可以在大多数情况下工作。

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

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

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;

如果你假设遵循LRM中的B.3(70)(从技术上来说这只是实现建议,但我认为这是一个安全的假设),那么你可以直接使用C_String导入 C 程序的接口(interface)代替 char* 参数:

function Open (Pathname : in     Strings_For_C.C_String;
               Flags    : in     Interfaces.C.int)
  return Interfaces.C.int;

关于string - 将字符串传递给 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29561601/

相关文章:

c++ - 给定字符串 vector (按长度排序),用于查找等长字符串范围的惯用 C++

c++ - 从字符串中读取所有整数 C++

java - 如何在 Java StringBuffer 中捕获某些文本

Ada 95 编译器版本更改,存在转换问题

ada - **Post** 合约中的 `' Old` 属性如何处理可能在函数或过程中被解除分配的访问类型?

docker - 在 Alpine Linux Docker 容器中构建 GNATCOLL

c - strcmp() 来自标准输入的字符串和来自文件的字符串

java - 如何为字符串数组中的每个元素添加一个字符串前缀?

regex - Ada 中的正则表达式?

ada - 防止在 GNAT 中使用 Ada 202x