首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法将void *转换为字节数组

无法将void *转换为字节数组
EN

Stack Overflow用户
提问于 2013-10-30 23:21:31
回答 5查看 1.8K关注 0票数 1

编辑:我简化了我的代码,以更好地显示情况。

任务:我有一个用C编写的工作套接字服务器/客户端程序,我想通过使用Ada接口来改进它。

C函数,当用户输入数学操作为2+5、5*9、10/2或10-9时,该函数将获取用户输入。

代码语言:javascript
复制
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;
}

客户端向服务器发送一个结构,如下所示:

代码语言:javascript
复制
typedef struct
{
     int number1;
     int number2;
     char operator;
}Operation;

Ada主要程序:

代码语言:javascript
复制
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“的包,它具有打开、关闭和读取客户端消息的功能和过程:

代码语言:javascript
复制
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类型)。

怎样才能使操作符完全结构化?

EN

回答 5

Stack Overflow用户

发布于 2013-11-01 07:05:03

你定义

代码语言:javascript
复制
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,这是'+‘。

若要正确地执行此操作,请声明

代码语言:javascript
复制
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");

然后你可以用

代码语言:javascript
复制
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将与一些编译器一起工作,但不适用于所有编译器。仅仅因为它与当前编译器一起工作并不意味着它将与另一个编译器一起工作,包括与当前编译器的不同版本一起工作。)

票数 2
EN

Stack Overflow用户

发布于 2013-10-31 04:04:32

嗯..。看来您可以使用包(以及泛型!)这里。

代码语言:javascript
复制
-- 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。

票数 1
EN

Stack Overflow用户

发布于 2013-11-01 08:11:13

如果希望编译器适合某个类型或变量,则应该显式地告诉它。

代码语言:javascript
复制
type Byte is range 0 .. 255;

仅使用上面的声明,可以为Byte类型分配从8位到更高的任何内容。可以添加大小声明,以指定所需的大小:

代码语言:javascript
复制
type Byte is range 0 .. 255;
for Byte'Size use 8;

现在编译器必须将Byte类型的变量设置为8位(或者编译源文本失败)。

对于无约束数组,其实现方式略有不同:

代码语言:javascript
复制
type Bytes is array (Integer range <>) of Byte;
pragma Pack (Bytes);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19695676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档