简体   繁体   English

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

[英]C & PHP: Storing settings in an integer using bitwise operators?

I'm not familiar with bitwise operators, but I have seem them used to store simple settings before. 我不熟悉按位运算符,但我似乎以前用它们存储简单的设置。

I need to pass several on/off options to a function, and I'd like to use a single integer for this. 我需要将几个开/关选项传递给一个函数,我想为此使用一个整数。 How can I go about setting and reading these options? 我该如何设置和阅读这些选项?

You sure can do it in PHP. 你肯定可以用PHP做到这一点。

Let's say you have four booleans you want to store in a single value. 假设您要将四个布尔值存储在单个值中。 That means we need four bits of storage space 这意味着我们需要四位存储空间

0000

Each bit, when set individually, has a unique representation in decimal 单独设置时,每个位都有一个十进制的唯一表示

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

A common way to implement this is with bit masks to represent each option. 实现此目的的常用方法是使用位掩码来表示每个选项。 PHP's error levels are done this way, for example. 例如,PHP的错误级别就是以这种方式完成的。

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

Then when you have an integer that represents 0 or more of these flags, you check with with the bitwise and operator which is & 然后当你有一个表示0或更多这些标志的整数时,你用bitwise和operator检查是&

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

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

This operator works as such: only bits that are set in both operands are set in the result 此运算符的工作方式如下:只在结果中设置在两个操作数中设置的位

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

If we checked it against OPT_2 , then the result would look like this 如果我们针对OPT_2进行了检查,那么结果将如下所示

0101 // our options
0010 // the value of OPT_2
----
0000 // The decimal integer 0 evaluates as "false" in an expression

It works pretty much the same way in both languages, a side by side comparison: 它在两种语言中的工作方式大致相同,并列比较:

C: 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:

<?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);

?>

Note, you don't absolutely need to use constants, I just use them out of habit. 注意,你并不一定需要使用常量,我只是出于习惯而使用它们。 Both examples will run, I compiled the C version via gcc -Wall flags.c -o flags . 这两个例子都会运行,我通过gcc -Wall flags.c -o flags编译了C版本。 Change flags in either example to anything but FLAG_TWO or FLAG_ALL and (sadly) no waffles will be made. 将示例中的flags更改为除FLAG_TWOFLAG_ALL任何内容,并且(遗憾地)不会FLAG_TWOFLAG_TWO饼。

In the C version, you don't have to tickle the preprocessor, it could quite easily be an enum, etc - that's an exercise for the reader. 在C版本中,您不必搔痒预处理器,它可以很容易地成为枚举等 - 这对读者来说是一种练习。

quote "the idea is not good, really. you would better pass few boolean. if you want use bitwise then 引用“这个想法并不好,真的。你最好传递几个布尔值。如果你想用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      
}

"

What you have done would be okay if you were checking for a single value, although not optimal, so checking that a bit is enabled, but lets say we wanted to be able to match any, or exact we could have the following methods 如果你检查单个值,虽然不是最佳值,你所做的就没关系,所以检查一下是否已启用,但是我们想要能够匹配任何一个,或者确切地说我们可以使用以下方法

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;
}

if you then wanted to expand upon this by having specific actions only happening if bit x,y,z was enabled then you could use the following 如果您想通过仅在启用位x,y,z的情况下执行特定操作来扩展此功能,那么您可以使用以下

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

I also think if you are doing what was done in the above quote, flags may not be the best idea, exact values might be better, which does have the benefit of allowing more discreet actions. 我也认为如果你正在做上面引用中所做的事情,标志可能不是最好的主意,确切的值可能更好,这确实有利于允许更谨慎的行动。 (0-255) for 8-bit over 8 distinct flags (0-255)对于8位超过8个不同的标志

The whole reason flags work so well is because in base 2 "8" does not contain "4", and "2" does not contain "1". 整个原因标志工作得很好是因为在基数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             |
 ------------------------

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM