Маска, управляющая битами [дубликат]

Если вы хотите строить его каждый раз вместе с вашим проектом, самым простым способом было бы:

  • Добавить исходный код где-нибудь в ваше дерево проекта
  • Добавить пользовательская цель CMake , которая должна запускаться до начала компиляции
  • . В этой настраиваемой цели запустите все, что необходимо для компиляции библиотеки (в вашем случае это ./configure -> make - > make install.

Однако это редко требуется, и в большинстве случаев вам нужно просто построить библиотеку один раз и связать ее как с любой другой внешней библиотекой.

21
задан Robert Gamble 25 November 2008 в 07:38
поделиться

5 ответов

~ (~ 0 & lt; m) & lt; п

41
ответ дан Darius Bacon 21 August 2018 в 09:46
поделиться
  • 1
    Это пятно. Тем не менее, было бы неплохо прокомментировать эту строку, потому что -next-программист должен работать над ней. – mkClark 26 November 2008 в 00:41
  • 2
    Если это было закодировано как функция (функции set_mask_n в ответе @ quinmar), был бы однострочный комментарий, говорящий о том, что делает функция (и никакой аргумент «k»), и пользователи функции будут иметь имя как документация. Будучи случайным выражением в немного кода, это было бы БЕСПЛАТНО! – Jonathan Leffler 27 November 2008 в 06:55
  • 3
    И я бы поспешил (очень медленно) добавить, мое решение было бы столь же непостижимо, если бы оно выглядело как недокументированное выражение в немного кода. – Jonathan Leffler 10 December 2008 в 02:56
  • 4
    ~(~0 << m) находится в пункте 2.9 «Побитовые операторы». «Язык программирования C, второе издание» Брайана Кернигана и Денниса Ричи. Это также в пункте 7.5 «Эффективность пространства». «Практика программирования» Брайана У. Кернигана и Роб Пайка. – Alessandro Jacopson 22 July 2011 в 07:57
  • 5
    Этот подход не может создать маску, включающую самый верхний бит самого длинного целочисленного типа , то есть обычно указывается с предупреждением типа integer overflow in preprocessor expression. – Barry 8 October 2015 в 02:35

Мне нравятся оба решения. Вот еще один способ, который приходит мне на ум (возможно, не лучше).

((~((unsigned int)0) << k) >> (k + n)) << n

ИЗМЕНИТЬ: В моей предыдущей версии произошла ошибка (это было без неподписанного int cast ). Проблема заключалась в том, что ~0 >> n добавляет 1s спереди, а не 0s.

И да, этот подход имеет один большой недостаток; он предполагает, что вы знаете количество бит целочисленного типа по умолчанию или, другими словами, оно предполагает, что вы действительно знаете k, тогда как другие решения не зависят от k. Это делает мою версию менее переносной или, по крайней мере, труднее переносить. (Он также использует 3 смены и добавление и оператор побитового отрицания, что является двумя дополнительными операциями.)

Таким образом, вам лучше использовать один из других примеров.

Здесь это небольшое тестовое приложение, сделанное Джонатаном Леффлером, для сравнения и проверки вывода различных решений:

#include <stdio.h>
#include <limits.h>

enum { ULONG_BITS = (sizeof(unsigned long) * CHAR_BIT) };

static unsigned long set_mask_1(int k, int m, int n)
{
    return ~(~0 << m) << n;
}

static unsigned long set_mask_2(int k, int m, int n)
{
    return ((1 << m) - 1) << n;
}

static unsigned long set_mask_3(int k, int m, int n)
{
    return ((~((unsigned long)0) << k) >> (k + n)) << n;
}

static int test_cases[][2] =
{
    { 1, 0 },
    { 1, 1 },
    { 1, 2 },
    { 1, 3 },
    { 2, 1 },
    { 2, 2 },
    { 2, 3 },
    { 3, 4 },
    { 3, 5 },
};

int main(void)
{
    size_t i;
    for (i = 0; i < 9; i++)
    {
        int m = test_cases[i][0];
        int n = test_cases[i][1];
        int k = ULONG_BITS - (m + n);
        printf("%d/%d/%d = 0x%08lX = 0x%08lX = 0x%08lX\n", k, m, n,
               set_mask_1(k, m, n),
               set_mask_2(k, m, n),
               set_mask_3(k, m, n));
    }
    return 0;
}
29
ответ дан Jonathan Leffler 21 August 2018 в 09:46
поделиться
  • 1
    Они оба работают, но я нахожу ответ Джонатана более простым и понятным. Ответ Дариуса слишком обратный мне. – Robert Gamble 25 November 2008 в 07:34
  • 2
    Роберт, мне нравится идиома ~ 0 для битмасков, потому что она не зависит от 2'-дополнения и в этом смысле проще, но это правда, что она менее известна. Просто сделай все, чтобы изменить это! – Darius Bacon 25 November 2008 в 08:10
  • 3
    @Darius: если вы используете неподписанную арифметику / типы, как вам следует в этих контекстах, разве не разница между 2'-дополнением, 1'-дополнением и арифметикой знаковой величины несущественна? – Jonathan Leffler 25 November 2008 в 08:18
  • 4
    @Darius, вы не должны выполнять поразрядную арифметику на подписанных типах в первую очередь, и если бы вы были, ваше решение каждый раз вызывает неопределенное поведение! – Robert Gamble 25 November 2008 в 08:20
  • 5
    Не определено? У меня нет спецификации под рукой, но я думаю, что это определенная реализация, т. Е. Компилятору разрешено делать это так, как он хочет, но он всегда должен делать это одинаково. Поэтому, когда вы знаете лечение (вашего компилятора), вы можете положиться на него. – flolo 25 November 2008 в 08:52
  • 6
    Исходя из предположения, что этот ответ можно заставить работать, очевидным недостатком по сравнению с двумя другими является наличие операции третьего сдвига, что делает ее более трудоемкой. – Jonathan Leffler 25 November 2008 в 15:45
  • 7
    Другая проблема заключается в том, что он использует параметр k, который два других решения могут игнорировать (он не использует m, хотя, тем не менее, он использует только два из трех параметров). – Jonathan Leffler 25 November 2008 в 15:46
  • 8
    Прямо там была ошибка, я исправил ее сейчас и добавил комментарий, что другие решения предпочтительнее. Я не удалял его полностью, может быть, кто-то может учиться на моих ошибках, и было бы грустно потерять ваш хороший тестовый код :). – quinmars 25 November 2008 в 20:34
  • 9
    Вместо трансляции вы должны использовать '0U', чтобы указать знак без знака, или '0UL', чтобы указать длину без знака. Я согласен с тем, чтобы оставить ваш ответ на месте - и с внесенными вами изменениями. – Jonathan Leffler 25 November 2008 в 22:06
  • 10
    Сделайте это макросом или встроенной функцией, компилятор будет генерировать константу во время компиляции вместо кода. – Barry 8 October 2015 в 02:48

В то время как верхние ответы просты и эффективны, они не устанавливают MSB для случая, когда n=0 и m=31:

~(~0 << 31) << 0 = 0111 1111 1111 1111 1111 1111 1111 1111‬

((1 << 31)-1) << 0 = 0111 1111 1111 1111 1111 1111 1111 1111‬

Мое предложение для 32-битного слова без знака (которое является уродливым и имеет ветвь) выглядит следующим образом:

unsigned int create_mask(unsigned int n,unsigned int m) {
  // 0 <= start_bit, end_bit <= 31
  return (m - n == 31 ? 0xFFFFFFFF : ((1 << (m-n)+1)-1) << n);
}

на самом деле получает бит в диапазоне [m,n] (закрытый интервал), поэтому create_mask(0,0) вернет маску для первого бита (бит 0) и create_mask(4,6) возвращает маску для битов с 4 по 6, т.е. ... 00111 0000.

0
ответ дан Nubcake 21 August 2018 в 09:46
поделиться

(только) Для тех, кто заинтересован в немного более эффективном решении для систем x86 с поддержкой BMI2 (Intel Haswell или новее, AMD Excavator или новее):

mask = _bzhi_u32(-1,m)<<n;

Инструкция bzhi нули старших бит, начиная с заданной позиции бита. Собственные компиляции _bzhi_u32 этой инструкции. Тестовый код:

#include <stdio.h>
#include <x86intrin.h>
/*  gcc -O3 -Wall -m64 -march=haswell bitmsk_mn.c   */

unsigned int bitmsk(unsigned int m, unsigned int n)
{
    return _bzhi_u32(-1,m)<<n;
}

int main() {
    int k = bitmsk(7,13);
    printf("k= %08X\n",k);
    return 0;
}

Выход:

$./a.out
k= 000FE000

Кодовый фрагмент _bzhi_u32(-1,m)<<n компилируется в три команды

movl    $-1, %edx
bzhi    %edi, %edx, %edi
shlx    %esi, %edi, %eax

Который является одной инструкцией меньше чем коды @Jonathan Leffler и @Darius Bacon . На процессорах Intel Haswell или новее оба bzhi и shlx имеют латентность 1 цикл и пропускную способность 2 за цикл. На AMD Ryzen эти две инструкции имеют пропускную способность 4 за цикл.

0
ответ дан wim 21 August 2018 в 09:46
поделиться
29
ответ дан Jonathan Leffler 1 November 2018 в 04:05
поделиться
Другие вопросы по тегам:

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