MicrosoftがGitHubでMITライセンス公開しているWILのGitHub Wikiからビット操作ヘルパーの記事を和訳・改変したものです。素人による翻訳なので、誤訳や著作権上の問題などありましたらご連絡いただけますと幸いです。
ビット演算ヘルパー
Duncan Horn、2020/7/17、リビジョン4個
ビット演算ヘルパー
wil/common.h
でビット演算の可読性改善とエラー率減少のために多数のヘルパーマクロを定義しています。
これらのマクロは操作を簡潔に表すことで可読性を改善します。フラグと変数はマクロの呼び出し毎に指定され、マクロの名前は操作の特性を説明します。
また、複雑なビット操作を1ステップにまとめることでエラーを減少させます。単一フラグ操作はコンパイル時に単一フラグだけが指定されたことを検証します。
例:
// 次のコードの代わり:days = days & ~DaysOfWeek::Monday; WI_ClearFlag(days, DaysOfWeek::Monday); // 次のコードの代わり:if ((days & (DaysOfWeek::Monday | DaysOfWeek::Tuesday)) == (DaysOfWeek::Monday | DaysOfWeek::Tuesday)) if (WI_AreAllFlagsSet(days, DaysOfWeek::Monday | DaysOfWeek::Tuesday))
フラグ操作
以下の表で使います。
var
は変数です。flag
はコンパイル時定数で2の指数(単一フラグ)です。 この要件はコンパイル時に実施されます。flags
、mask
、newFlags
は実行時の値またはコンパイル時定数です。0から複数個のフラグで構成できます。cond
は論理型(boolean)の条件式です。
マクロは記述のようにvar
の値を変更します。
マクロ | 操作 |
---|---|
WI_SetFlag(var, flag); |
単一ビットを設定します。 |
WI_SetFlagIf(var, flag, cond); |
cond がtrue なら単一ビットを設定します。 |
WI_SetAllFlags(var, flags); |
0から複数個のビットを設定します。 |
WI_ClearFlag(var, flag); |
単一ビットをクリアします。 |
WI_ClearFlagIf(var, flag, cond); |
cond がtrue なら単一ビットをクリアします。 |
WI_ClearAllFlags(var, flags); |
0から複数個のビットをクリアします。 |
WI_UpdateFlag(var, flag, cond); |
cond がtrue なら単一ビットを設定して、cond がfalse なら単一ビットをクリアします。 |
WI_UpdateFlagsInMask(var, mask, newFlags); |
mask で指定された部分フラグをnewFlags に対応するビットに変換します。 |
WI_ToggleFlag(var, flag); |
単一ビットをトグル(XOR)します。 |
WI_ToggleAllFlags(var, flags); |
0から複数個のビットをトグル(XOR)します。 |
フラグ検査
以下の表で使います。
val
は式です。flag
はコンパイル時定数で2の指数(単一フラグ)です。この要件はコンパイル時に施行されます。flags
、mask
、newFlags
は実行時の値またはコンパイル時定数です。0から複数個のフラグで構成できます。
マクロは記述のようにval
の値をテストして、条件に一致すればtrue
、一致しなければfalse
を返します。
マクロ | 条件 |
---|---|
WI_IsFlagSet(val, flag) |
flag で指定したビットがval に設定されている。 |
WI_IsAnyFlagSet(val, flags) |
flags で指定したビットのいずれかがval に設定されている。 |
WI_AreAllFlagsSet(val, flags) |
flags で指定したビットのすべてがval に設定されている。 |
WI_IsFlagClear(val, flag) |
flag で指定したビットがval に設定されていない。 |
WI_IsAnyFlagClear(val, flags) |
flags で指定したビットのいずれかがval に設定されていない。 |
WI_AreAllFlagsClear(val, flags) |
flags で指定したビットのすべてがval に設定されていない。 |
WI_IsSingleFlagSet(val) |
val は単一ビットだけ設定されている。 |
WI_IsSingleFlagSetInMask(val, mask) |
val はmask で指定したビットだけ設定されている。 |
WI_IsClearOrSingleFlagSet(val) |
val は高々1ビットが指定されている。 |
WI_IsClearOrSingleFlagSetInMask(val, mask) |
val はmask で指定したビットの高々1ビットが指定されている。 |
例
enum class DaysOfWeek { None = 0x0000, Sunday = 0x0001, Monday = 0x0002, Tuesday = 0x0004, Wednesday = 0x0008, Thursday = 0x0010, Friday = 0x0020, Saturday = 0x0040, }; DEFINE_ENUM_FLAG_OPERATORS(DaysOfWeek); extern DaysOfWeek GetAvailableDays(); DaysOfWeek days = DaysOfWeek::Sunday; WI_SetFlag(days, DaysOfWeek::Saturday); // 結果:days = Sunday | Saturday WI_ClearFlag(days, DaysOfWeek::Sunday); // 結果:days = Saturday WI_SetAllFlags(days, DaysOfWeek::Monday | DaysOfWeek::Tuesday); // 結果:days = Monday | Tuesday | Saturday WI_SetFlagIf(days, DaysOfWeek::Friday, false); // 結果:days = Monday | Tuesdy | Saturday (unchanged) WI_ToggleFlag(days, DaysOfWeek::Monday); // 結果:days = Tuesday | Saturday WI_UpdateFlag(days, DaysOfWeek::Monday, false); // 結果:days = Tuesday | Saturday // Mondayを設定してTuesdayをクリアします。Wednesdayは影響しません。 WI_UpdateFlagsInMask(days, DaysOfWeek::Monday | DaysOfWeek::Tuesday, DaysOfWeek::Monday | DaysOfWeek::Wednesday); // 結果:days = Monday | Saturday if (WI_IsFlagSet(days, DaysOfWeek::Sunday)) ... // false if (WI_AreAllFlagsSet(days, GetAvailableDays()) ... if (WI_AreAllFlagsClear(days, GetAvailableDays()) ... // 単一ビットだけ設定されているかテストします。 if (WI_IsSingleFlagSet(days)) ... // false
次の使い方はコンパイルできないでしょう。
WI_SetFlag(days, DaysOfWeek::None); // エラー // 代わりにUse WI_SetAllFlags insteadを使います。 WI_SetFlag(days, DaysOfWeek::Thursday | DaysOfWeek::Friday); // エラー // 代わりにWI_SetAllFlagsを使います。 WI_SetFlag(days, GetAvailableDays()); // エラー if (WI_IsFlagSet(days, DaysOfWeek::None)) // エラー // エラー // 求める結果によりWI_AreAllFlagsSetまたはWI_IsAnyFlagSetを使います。 if (WI_IsFlagSet(days, DaysOfWeek::Sunday | DaysOfWeek::Saturday)) // エラー
他のヘルパー
WI_EnumValue
WI_EnumValue
マクロは与えられた列挙値(enum
の値)と幅および値の同じ符号なし整数を返します。これはenum
のフィールドがその他の整数の組み合わせに一致するか検証するときに便利です。
enum class DropEffects { None = 0x0000, Copy = 0x0001, Move = 0x0002, Link = 0x0004, }; static_assert(WI_EnumValue(DropEffects::None) == DROPEFFECT_NONE); static_assert(WI_EnumValue(DropEffects::Copy) == DROPEFFECT_COPY); static_assert(WI_EnumValue(DropEffects::Move) == DROPEFFECT_MOVE); static_assert(WI_EnumValue(DropEffects::Link) == DROPEFFECT_LINK);
WI_StaticAssertSingleBitSet
値が正確に2の指数でない場合にコンパイラにエラーを強制します。元の値を返します。このマクロは典型的に他のビット操作マクロで使用されます。
if (effect & WI_StaticAssertSingleBitSet(DropEffects::Copy))
{
...
}
著作権表示
この記事は以下の著作物を使用しています。
Copyright (c) Microsoft Corporation. All rights reserved. https://github.com/microsoft/wil/blob/master/LICENSE