C から 16 ビット整数を取得します。この整数は 16 個のフラグで構成されます。
この整数を16個のブール値のレコードに変換するにはどうすればよいですか?
ありがとう!
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関数instadの宣言で直接使用できます。
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が指摘したように、コードをリトルエンディアンのマシンで実行するだけでよい限り、これは問題ありません。SPARCまたはPowerbookで実行したい場合は、trashgodの提案を使用するのがおそらく最善です。
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
単純に 16 の右ビット シフトを実行し、ビット単位の AND を結果と 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
Ada では、モジュラー型により、論理演算でビット セットとして値にアクセスできます。Ada 95 で導入された概要は、Ada 95 Rationale, §3.3.2 Modular Types にあります。実装によっては、定義済みの型Interfaces.C.unsigned_short
が C から値を取得するための便利な選択肢になる場合があります。
オーバーレイを使用して、目的の結果を達成することもできます。これらのブール値はすべて意味があり、厳密にブール値である (つまり、列挙型のものは何もない) と仮定しましょう。
まず、レコードを定義する必要があります。説明するために 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;
短いint(またはint_16)とビットフィールドを含む和集合を使用できます。
union UMyFlags {
short n;
struct {
flag_1 : 1;
flag_2 : 1;
// other flags ...
} flags;
};
ただし、バイト順序のため、コードはすべてのプラットフォームで移植可能ではありません。