C & PHP: Хранение настроек в целом числе с помощью побитовых операторов?

Я не знаком с побитовыми операторами, но я имею, кажутся ими, раньше хранил простые настройки прежде.

Я должен передать несколько опций включения - выключения функции, и я хотел бы использовать единственное целое число для этого. Как я могу пойти об установке и чтении этих опций?

15
задан John Coates 5 May 2010 в 14:07
поделиться

3 ответа

Вы точно можете это сделать в 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
34
ответ дан 1 December 2019 в 00:41
поделиться

quote "идея не очень хорошая, на самом деле. лучше передавать несколько булевых чисел. если вы хотите использовать bitwise then

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             |
 ------------------------
2
ответ дан 1 December 2019 в 00:41
поделиться

Он работает практически одинаково на обоих языках, параллельное сравнение:

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 flags . Измените flags в любом примере на что угодно, кроме FLAG_TWO или FLAG_ALL , и (к сожалению) вафли не будут.

В версии C вам не нужно щекотать препроцессор, это вполне может быть перечисление и т. Д. - это упражнение для читателя.

8
ответ дан 1 December 2019 в 00:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: