编辑:我简化了我的代码,以更好地显示情况。
任务:我有一个用C编写的工作套接字服务器/客户端程序,我想通过使用Ada接口来改进它。
C函数,当用户输入数学操作为2+5、5*9、10/2或10-9时,该函数将获取用户输入。
int read_message(void *buffer, int size, int timeout)
{
//Recevie
int n = recv(newfd, buffer, size, 0);
if(n == -1)
{
perror("Can not read message");
return -1;
}
return 1;
}客户端向服务器发送一个结构,如下所示:
typedef struct
{
int number1;
int number2;
char operator;
}Operation;Ada主要程序:
with Ada.Text_IO, communication_pkg, Ada.Exceptions, Interfaces.C;
use Ada.Text_IO, communication_pkg;
procedure Main is
package C_pkg renames communication_pkg;
begin
Put_Line(Integer'Image(C_pkg.open_communication));
Put_Line("Server is Open");
C_pkg.read_message;
exception
when Event: Open_Error =>
Put_Line("Can not open connection");
New_Line;
Put_Line(Ada.Exceptions.Exception_Name(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Message(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Information(Event));
when Event: Close_Error =>
Put_Line("Can not close connection");
New_Line;
Put_Line(Ada.Exceptions.Exception_Name(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Message(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Information(Event));
when Event: Can_not_read_error =>
Put_Line("Can not read");
New_Line;
Put_Line(Ada.Exceptions.Exception_Name(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Message(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Information(Event));
when Event: Read_timeout_error =>
Put_Line("Read timeout");
New_Line;
Put_Line(Ada.Exceptions.Exception_Name(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Message(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Information(Event));
when Event: others =>
Put_Line("Something else went wrong");
New_Line;
Put_Line(Ada.Exceptions.Exception_Name(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Message(Event));
New_Line;
Put_Line(Ada.Exceptions.Exception_Information(Event));
end Main;称为"communication_pkg“的包,它具有打开、关闭和读取客户端消息的功能和过程:
with Interfaces.C, Ada.Unchecked_COnversion, Ada.Text_IO;
use Interfaces.C, Ada.Text_IO;
with System;
package body Communication_pkg is
package C renames Interfaces.C;
function open return Integer;
pragma Interface(C, open);
pragma Interface_Name(open, "open");
function close return Integer;
pragma Interface(C, close);
pragma Interface_Name(close, "close_connection");
function read(buffer: in System.Address; size : in Integer; timeout: in Integer) return Integer;
pragma Interface(C,read);
pragma Interface_Name(read, "read_message");
function open_communication return Integer is
connection_status : Integer;
begin
connection_status := open;
if (connection_status = -1) then
raise Open_Error;
end if;
return connection_status;
end open_communication;
function close_communication return Integer is
connection_status : Integer;
begin
connection_status := close;
if(connection_status = -1) then
raise Close_Error;
end if;
return connection_status;
end close_communication;
procedure read_message is
size : Integer:=9;
timeout : Integer:=1;
read_message_status : Integer;
type byte is range 0..255;
type byte_array is array (Integer range 0..15) of byte;
--buffer : System.Address
buffer : byte_array;
begin
Put_Line("read message in");
read_message_status:=read(buffer'Address, size, timeout);
Put_Line(Integer'Image(read_message_status));
if(read_message_status = -1) then
raise Can_not_read_error;
elsif(read_message_status = -2) then
raise Read_timeout_error;
end if;
Put_Line("read message out");
for i in 0..15 loop
Put_Line(byte'Image(buffer(i)));
end loop;
end;
end Communication_pkg;主过程首先打开连接并等待从客户端接收消息。当客户端发送一个类型操作的结构时,当客户端输入2+5时,我在缓冲区中得到的内容如下所示:
2 0 5 0 0 12331 11444 32688 0 2848 2737 32688 0 8864 64399 32767 0
缓冲区中的第一个字节和第三个字节(类型为byte_array)总是显示客户机输入的第一个和第二个整数。但是,缓冲区没有运算符(char类型)。
怎样才能使操作符完全结构化?
发布于 2013-11-01 07:05:03
你定义
type byte is range 0..255;Ada要求有符号整数类型(用“range”定义)的基类型为有符号整数类型,大致对称于零,其范围足够大,足以容纳类型声明中的范围。这意味着基本类型的Byte必须足够大,足以容纳-255。255。所以Byte‘’Base可能是一个16位的,有符号的,两位的补整数.而且,实际上,您的结果包含诸如12331这样的值,这些值太大,不适合0 ..255。
C在你的系统上似乎是32位,小endian。这就是为什么每个int得到两个值的原因,操作数在第一个单词中,在第二个单词中为零。这意味着运算符将在第五个单词的LSB中。
实际上,12331雷姆256 = 43,这是'+‘。
若要正确地执行此操作,请声明
type Byte is mod 256;
pragma Convention (C, Byte);
type Byte_List is array (Interfaces.C.int range 0 .. 15) of Byte;
pragma Convention (C, Byte_List);
function Read (List : Byte_List; Size : Interfaces.C.Int; Timeout : Interfaces.C.Int)
return Interfaces.C.Int;
pragma Import (C, Read, "read_message");然后你可以用
Status : Interfaces.C.Int;
List : Byte_List;
...
Status := Read (List, 9, 1);你应该发现这个列表包含了
2 0 0 0 5 0 0 0 43
重要规则:
传递给C函数的一切都应该是约定C(是的,有时非约定-C类型可以工作,但有时它们不能工作,而约定-C类型总是工作的)。
永远不要将System.Address传递给C。要传递数组,只需传递数组;Ada将指向数组第一个元素的约定-C指针传递给C函数,为您提供您想要的。在需要指针的其他情况下,您应该传递约定-C访问类型。(System.Address将与一些编译器一起工作,但不适用于所有编译器。仅仅因为它与当前编译器一起工作并不意味着它将与另一个编译器一起工作,包括与当前编译器的不同版本一起工作。)
发布于 2013-10-31 04:04:32
嗯..。看来您可以使用包(以及泛型!)这里。
-- We need to define the base-type for the buffer.
Subtype Byte_Array is Interfaces.C.char_array;
-- Taking an address for the size (size_t type), and an address for the
-- location of the buffer we create one with the package's instantiation.
Generic
Buffer_Location,
Size_Location : in System.Address;
Package Buffer_Package is
Length : constant Interfaces.C.size_t
with Address => Size_Location, Import, Convention => C;
Subtype Buffer_Type is Byte_Array(1..Length);
Buffer : Buffer_Type
with Address => Buffer_Location, Import, Convention => C;
Pragma Assert( Length >= 0 );
End Buffer_Package;
Generic
with package Buf_Pkg is new Buffer_Package( others => <> );
Package Parse is
Type Operators is ( Identity, '*', '/', '+', '-' );
-- There are three forms of Node:
-- 1) Unary operation: only the string-field "right" exists.
-- 2) Binary operation #1: in addition to "Right" is the string "Left"
-- 3) Binary operation #2: in addition to "Right" is a pointer to a node.
Type Node( Op : Operators; Len_1, Len_2 : Natural ) is record
Right : String(1..Len_1);
case Op is
when Identity => null;
when others =>
case Len_2 is
when Positive => Left : String(1..Len_2);
when 0 => Ptr : not null access Node;
end case;
end case;
end record;
Function Exec( Input : Node ) return Float;
-- YOUR READ FUNCTION HERE! (Use Buf_Pkg.Buffer.)
private
Function Value( Input : Node ) return Float;
end Parse;
Package body Parse is
Function Exec( Input : Node ) return Float renames Value;
Function Value( Input : Node ) return Float is
Subtype Unary is Operators range Identity..Identity;
begin
declare
Right : constant Float:= Float'value(Input.Right);
Left : constant Float:= (if Input.Op in Unary then 0.0 else
(if Input.Len_2 in Positive then Float'value(Input.Left)
else Value(Input.Ptr.all)
));
begin
case Input.Op is
when Identity => return Right;
when '*' => return Left * Right;
when '/' => return Left / Right;
when '+' => return Left + Right;
when '-' => return Left - Right;
end case;
end;
end Value;
end Parse;将从缓冲区读取到Node-tree作为练习留给OP。
发布于 2013-11-01 08:11:13
如果希望编译器适合某个类型或变量,则应该显式地告诉它。
type Byte is range 0 .. 255;仅使用上面的声明,可以为Byte类型分配从8位到更高的任何内容。可以添加大小声明,以指定所需的大小:
type Byte is range 0 .. 255;
for Byte'Size use 8;现在编译器必须将Byte类型的变量设置为8位(或者编译源文本失败)。
对于无约束数组,其实现方式略有不同:
type Bytes is array (Integer range <>) of Byte;
pragma Pack (Bytes);https://stackoverflow.com/questions/19695676
复制相似问题