C& PHP:使用按位运算符将整数设置存储?

时间:2010-05-05 14:07:29

标签: php c bit-manipulation bitwise-operators

我不熟悉按位运算符,但我似乎以前用它们来存储简单的设置。

我需要将几个开/关选项传递给一个函数,我想为此使用一个整数。我怎样才能设置和阅读这些选项?

3 个答案:

答案 0 :(得分:33)

你确定可以在PHP中完成。

假设您要将四个布尔值存储在单个值中。这意味着我们需要四位存储空间

0000

每个位单独设置时,具有十进制的唯一表示

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

答案 1 :(得分: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);

?>

注意,你并不一定需要使用常量,我只是出于习惯而使用它们。这两个例子都会运行,我通过gcc -Wall flags.c -o flags编译了C版本。将示例中的flags更改为除FLAG_TWOFLAG_ALL以外的任何内容,并且(遗憾地)不会制作华夫饼。

在C版本中,你必须搔痒预处理器,它很容易成为枚举等 - 这对读者来说是一种练习。

答案 2 :(得分:2)

报价 “这个想法并不好,真的。你最好传递一些布尔值。如果你想用bitwise那么

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) { // meets your criterion, as would a switch, case, but ultimately not suited for use with flags
    return $in === $match;
}

function matchAny($in, $match) { // meets original criterion with more lexical name however it returns true if any of the flags are true
    return $in |= $match;
}

如果您想通过仅在启用位x,y,z的情况下执行特定操作来扩展此操作,那么您可以使用以下

function matchHas($in, $match) { // more bitwise than === as allows you to conditionally branch upon specific bits being set
    return $in &= $match;
}

我也认为如果你正在做上面引用中所做的事情,标志可能不是最好的主意,确切的值可能更好,这确实有利于允许更谨慎的行动。 (0-255)8位超过8个不同的标志

整个原因标志工作得很好是因为在基数2“8”中不包含“4”,而“2”不包含“1”。

 ________________________
 |8|4|2|1|Base 10 Value |
 ------------------------
 |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             |
 ------------------------