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

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

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

Ответ 1

Вы можете сделать это на 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

Ответ 2

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

С

#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 вам не нужно щекотать препроцессор, это может быть легко перечислить и т.д. - это упражнение для читателя.

Ответ 3

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

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