16

私はビット演算子に精通していませんが、以前は単純な設定を格納するために使用されていたようです。

関数にいくつかのオン/オフオプションを渡す必要があります。これには単一の整数を使用したいと思います。これらのオプションを設定して読むにはどうすればよいですか?

4

3 に答える 3

37

あなたは確かにPHPでそれを行うことができます。

1つの値に格納するブール値が4つあるとします。つまり、4ビットのストレージスペースが必要です

0000

各ビットは、個別に設定すると、10進数で一意に表現されます。

0001 = 1 // or 2^0
0010 = 2 // or 2^1
0100 = 4 // or 2^2
1000 = 8 // or 2^3

これを実装する一般的な方法は、各オプションを表すビットマスクを使用することです。たとえば、PHPのエラーレベルはこの方法で行われます。

define( 'OPT_1', 1 );
define( 'OPT_2', 2 );
define( 'OPT_3', 4 );
define( 'OPT_4', 8 );

次に、これらのフラグの0個以上を表す整数がある場合は、ビット単位の演算子でチェックします。&

$options = bindec( '0101' );
// can also be set like this
// $options = OPT_1 | OPT_3;

if ( $options & OPT_3 )
{
  // option 3 is enabled
}

この演算子はそのように機能します。両方のオペランドに設定されたビットのみが結果に設定されます。

0101 // our options
0100 // the value of OPT_3
----
0100 // The decimal integer 4 evaluates as "true" in an expression

に対してチェックするとOPT_2、結果は次のようになります。

0101 // our options
0010 // the value of OPT_2
----
0000 // The decimal integer 0 evaluates as "false" in an expression
于 2010-05-05T14:30:43.177 に答える
8

両方の言語でほぼ同じように機能し、並べて比較します。

C:

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

#define FLAG_ONE 0x0001
#define FLAG_TWO 0x0002
#define FLAG_THREE 0x0004
#define FLAG_FOUR 0x0008
#define FLAG_ALL (FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR)

void make_waffles(void)
{
   printf("Yummy! We Love Waffles!!!\n");
}

void do_something(uint32_t flags)
{
    if (flags & FLAG_TWO)
         make_waffles();
}

int main(void)
{
    uint32_t flags;

    flags |= FLAG_ALL;

    /* Lets make some waffles! */
    do_something(flags);

    return 0;
}

PHP:

<?php

define("FLAG_ONE", 0x0001);
define("FLAG_TWO", 0x0002);
define("FLAG_THREE", 0x0004);
define("FLAG_FOUR", 0x0008);
define("FLAG_ALL", FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR);

function make_waffles()
{
    echo 'Yummy! We Love Waffles!!!';
}

function do_something($flags)
{
    if ($flags & FLAG_TWO)
       make_waffles();
}

$flags |= FLAG_TWO;
do_something($flags);

?>

注意してください、あなたは絶対に定数を使う必要はありません、私は習慣からそれらを使うだけです。両方の例が実行されます。Cバージョンをでコンパイルしましたgcc -Wall flags.c -o flagsflagsいずれかの例をFLAG_TWOor以外に変更するFLAG_ALLと、(悲しいことに)ワッフルは作成されません。

Cバージョンでは、プリプロセッサをくすぐる必要はありません。非常に簡単に列挙型などになる可能性があります。これは、読者にとっての演習です。

于 2010-05-05T14:33:13.220 に答える
2

引用「アイデアは本当に良くありません。いくつかのブール値を渡す方がよいでしょう。ビット単位で使用したい場合は、

function someFunc($options)
{

   if ($options & 1 != 0)
      //then option 1 enabled
   if ($options & (1 << 1) != 0)
      //then option 2 enabled      
   if ($options & (1 << 2) != 0)
      //then option 3 enabled      
}

「」

最適ではありませんが、単一の値をチェックしている場合は問題ありません。ビットが有効になっていることを確認しますが、任意の値に一致させたい、または正確に次の方法を使用できるようにしたいとします。

function matchExact($ in、$ match){// switch、caseのように基準を満たしていますが、最終的にはフラグでの使用には適していません
    $ in ===$match;を返します。
}

function matchAny($ in、$ match){//より多くの字句名で元の基準を満たしますが、フラグのいずれかがtrueの場合はtrueを返します
    $ in | =$match;を返します。
}

次に、ビットx、y、zが有効になっている場合にのみ特定のアクションを実行することでこれを拡張したい場合は、次を使用できます。

function matchHas($ in、$ match){//特定のビットが設定されたときに条件付きで分岐できるように===よりビット単位で
    $ in&=$match;を返します。
}

また、上記の引用で行われたことを実行している場合、フラグは最善のアイデアではない可能性があり、正確な値の方が優れている可能性があります。これには、より慎重なアクションを許可するという利点があります。(0-255)8ビットオーバー8個の異なるフラグの場合

フラグがうまく機能する理由は、ベース2では「8」に「4」が含まれておらず、「2」に「1」が含まれていないためです。

________________________
 | 8 | 4 | 2 |1|基数10の値|
 ------------------------
 | 1 | 1 | 1 | 1 | 15 |
 | 1 | 1 | 1 | 0 | 14 |
 | 1 | 1 | 0 | 1 | 13 |
 | 1 | 1 | 0 | 0 | 12 |
 | 1 | 0 | 1 | 1 | 11 |
 | 1 | 0 | 1 | 0 | 10 |
 | 1 | 0 | 0 | 1 | 9 |
 | 1 | 0 | 0 | 0 | 8 |
 | 0 | 1 | 1 | 1 | 7 |
 | 0 | 1 | 1 | 0 | 6 |
 | 0 | 1 | 0 | 1 | 5 |
 | 0 | 1 | 0 | 0 | 4 |
 | 0 | 0 | 1 | 1 | 3 |
 | 0 | 0 | 1 | 0 | 2 |
 | 0 | 0 | 0 | 1 | 1 |
 | 0 | 0 | 0 | 0 | 0 |
 ------------------------
于 2010-05-05T14:18:29.443 に答える