5

我从 C 中得到一个 16 位整数。这个整数由 16 个标志组成。

如何在 16 个布尔值的记录中转换此整数?

谢谢!

4

6 回答 6

4
type Flags is record
   Flag1 : Boolean;
   Flag2 : Boolean;
   - ...
   Flag15 : Boolean;
end record;

for Flags use record
   Flag1  at 0 range 0 .. 0;
   Flag2  at 0 range 1 .. 1;
   -- ...
   Flag15 at 0 range 15 .. 15;
 end record;
 for Flags'Size use 16;

 -- This is vital, because normally, records are passed by-reference in Ada.
 -- However, as we use this type with C, it has to be passed by value.
 -- C_Pass_By_Copy was introduced in GNAT and is part of the language since Ada 2005.
 pragma Convention (C_Pass_By_Copy, Flags);

您可以直接在 C 整数类型的导入 C 函数的声明中使用此类型。

于 2012-07-10T14:03:28.280 回答
3

您可以简单地执行 16 次右位移并将结果与​​ 1 逐位与来确定是否设置了位/标志。这是一个例子(我希望这不是家庭作业):

#include <stdio.h>
#include <stdint.h>

typedef unsigned char BOOL;

int main(void)
{
   unsigned i;
   uint16_t flags = 0x6E8B; /* 0b0110111010001011 */
   BOOL arr[16];

   for (i = 0; i < 16; i++) {
      arr[i] = (flags >> i) & 1;
      printf("flag %u: %u\n", i+1, arr[i]);
   }

   return 0;
}

arr[0]将包含最低有效位和arr[15]最高有效位。

输出:

flag 1: 1
flag 2: 1
flag 3: 0
flag 4: 1
flag 5: 0
flag 6: 0
flag 7: 0
flag 8: 1
flag 9: 0
flag 10: 1
flag 11: 1
flag 12: 1
flag 13: 0
flag 14: 1
flag 15: 1
flag 16: 0
于 2012-07-10T07:08:18.583 回答
3

在 Ada 中,您通常可以声明一个导入函数以获取所需类型的参数或返回值,而不是您必须转换的 C 等效类型。

所以,在这里,你想要

type Flags is array (0 .. 15) of Boolean;
for Flags'Component_Size use 1;
for Flags'Size use 16;
pragma Convention (C, Flags);

你可以将你的函数声明为

function Get_Flags return Flags;
pragma Import (C, Get_Flags, “get_flags");

其中与

unsigned short get_flags(void) {
  return 0x6e8b;
}

一个简单的安全带给了我

flag 0 is TRUE
flag 1 is TRUE
flag 2 is FALSE
flag 3 is TRUE
flag 4 is FALSE
flag 5 is FALSE
flag 6 is FALSE
flag 7 is TRUE
flag 8 is FALSE
flag 9 is TRUE
flag 10 is TRUE
flag 11 is TRUE
flag 12 is FALSE
flag 13 is TRUE
flag 14 is TRUE
flag 15 is FALSE

正如 Bo Persson 所说,只要您的代码只需要在 little-endian 机器上运行就可以了。如果您希望它在 SPARC 或 Powerbook 上运行,最好使用垃圾神的建议;

subtype Flags is Interfaces.C.unsigned_short;
use type Flags;

function Get_Flags return Flags;
pragma Import (C, Get_Flags, "get_flags");

然后,可能,命名你的标志位(用更有意义的东西!)

Flag_3 : constant Flags := 2#0000_0000_0000_1000#;

或(可能更像 C)

Flag_4 : constant Flags := 2 ** 4;

然后检查

(Get_Flags and Flag_3) /= 0
于 2012-07-10T14:07:35.610 回答
2

在 Ada 中,模块化类型允许逻辑操作以位集的形式访问值。在 Ada 95 中引入,可以在Ada 95 Rationale, §3.3.2 Modular Types中找到概述。根据实现,预定义类型Interfaces.C.unsigned_short可能是从 C 中获取值的方便选择。

于 2012-07-10T12:11:46.047 回答
1

您也可以使用叠加来达到预期的效果;让我们假设这些布尔值都是有意义的并且是严格的布尔值(即没有什么是枚举)。

首先你需要定义你的记录;我将使用单个 Nybble 来说明,但原理是适用的。Nybble 是旧的 DOS 属性:读取(可见性;回想起来应该是 Is_Hidden)、写入、存档和系统。

Type Nyble_Data is mod 2**4;
For Nyble_Data'Size use 4;

Type Data_Record is record
    Can_Read, Can_Write, Is_Archived, Is_System : Boolean:= False;
end record;

-- Ensure 4 bits used.
pragma Pack (Data_Record);
For Data_Record'Size use 4;

-- Specify Layout.
For Data_Record use
    record
        Can_Read    at 0 range 0..0;
        Can_Write   at 0 range 1..1;
        Is_Archived at 0 range 2..2;
        Is_System   at 0 range 3..3;
    end record;

-- This is where the magic occurs.
Function Convert( Data : In Nyble_Data ) Return Data_Record is
    Result : Data_Record;
    For Result'Address use Data'Address;
    Pragma Import( Convention => Ada, Entity => Result );
    Pragma Inline( Convert );
begin
    Return Result;
end Convert;

-- Test variables.
Input   : Nyble_Data:= 5;
Output  : Data_Record:= Convert(Input);

-- Display the record.
Procedure Put( Data : In Data_Record ) is
    Use Ada.Text_IO;
begin
    Put_Line( "Read:   "    & ASCII.HT & Boolean'Image(Data.Can_Read) );
    Put_Line( "Write:  "    & ASCII.HT & Boolean'Image(Data.Can_Write) );
    Put_Line( "Archive:"    & ASCII.HT & Boolean'Image(Data.Is_Archived) );
    Put_Line( "System: "    & ASCII.HT & Boolean'Image(Data.Is_System) );
end Put;
于 2012-07-10T20:37:27.250 回答
0

您可以使用包含一个短整数(或一个 int_16)和一个位字段的联合:

union UMyFlags {
    short n;
    struct {
        flag_1 : 1;
        flag_2 : 1;
        // other flags ...
    } flags;
};

但是,由于字节顺序,您的代码不会在每个平台上都可移植。

于 2012-07-10T07:36:52.083 回答