我正在研究将字符串传递给 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/