Битовые манипуляции C ++ компилируются без ошибок в моей системе, но компиляторы Godbolt выдают предупреждение / ошибки - PullRequest
0 голосов
/ 23 июня 2019

Редактировать: ссылка Godbolt, например здесь !

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

#include <bitset>
#include <iostream>

#define bit_mask(size, offset) (~(~0 << size) << offset)
#define bit_masked_set(dst, src, mask, offset) (dst = (dst & ~mask) | (src << offset))
#define bit_masked_get(src, mask, offset) ((src & mask) >> offset)

constexpr unsigned front_mask = bit_mask(16, 16);
constexpr unsigned back_mask = bit_mask(16, 0);

int main() {
    std::cout << std::bitset<32>(front_mask) << " = front_mask (bit_mask(16, 16))\n";
    std::cout << std::bitset<32>(back_mask) << " = back_mask (bit_mask(16, 0))\n\n";

    unsigned value = 0;
    std::cout << std::bitset<32>(value) << " = value (initial)\n\n";

    bit_masked_set(value, 1, front_mask, 16);
    std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, front_mask, 16))\n\n";

    bit_masked_set(value, 1, back_mask, 0);
    std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, back_mask, 0))\n\n";

    std::cout << std::bitset<32>(value) << " = value (final)\n";
}

Какие выходы:

11111111111111110000000000000000 = front_mask (bit_mask(16, 16))
00000000000000001111111111111111 = back_mask (bit_mask(16, 0))

00000000000000000000000000000000 = value (initial)

00000000000000010000000000000000 = value (after bit_masked_set(value, 1, front_mask, 16))

00000000000000010000000000000001 = value (after bit_masked_set(value, 1, back_mask, 0))

00000000000000010000000000000001 = value (final)

Я использую Visual Studio 2017 с -Wall -c ++ 17 и доволен этим. Но я заметил, что когда я вставил его в сайт Godbolt, gcc / clang / etc выдает предупреждения и / или ошибки в таких вещах, как:

error: constexpr variable 'front_mask' must be initialized by a constant expression
...
error: left operand of shift expression '(-1 << 16)' is negative [-fpermissive]
...
etc

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

Edit2:

Я поэкспериментировал с этим и обнаружил, что меняю макрос bit_mask на:

#define bit_mask(size, offset) (~((unsigned long long)~0 << size) << offset)

, похоже, решил проблему. Я не уверен на 100%, если мне понадобятся дополнительные long long, но я предполагаю, что это не повредит, это что-нибудь, это будет более гибким.

Edit3:

Значительно обновленный код из макросов в простую структуру:

#include <bitset>
#include <iostream>
#include <type_traits>

struct BitMask {
    using Mask_Type = unsigned long long;

    Mask_Type mask;
    unsigned offset;

    constexpr BitMask(unsigned size, unsigned offset) :
        mask{~((Mask_Type)~0 << size) << offset},
        offset{offset} {
    }

    template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
    constexpr T set_bits(T& dst, T src) const {
        return dst = (dst & ~mask) | (src << offset);
    }

    template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
    constexpr T get_bits(T src) const {
        return (src & mask) >> offset;
    }
};

constexpr BitMask front_mask = BitMask(16, 16);
constexpr BitMask back_mask = BitMask(16, 0);

int main() {
    std::cout << std::bitset<32>(front_mask.mask) << " = front_mask (bit_mask(16, 16))\n";
    std::cout << std::bitset<32>(back_mask.mask) << " = back_mask (bit_mask(16, 0))\n\n";

    unsigned value = 0;
    std::cout << std::bitset<32>(value) << " = value (initial)\n\n";

    front_mask.set_bits(value, 1U);
    std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, front_mask, 16))\n\n";

    back_mask.set_bits(value, 1U);
    std::cout << std::bitset<32>(value) << " = value (after bit_masked_set(value, 1, back_mask, 0))\n\n";

    std::cout << std::bitset<32>(value) << " = value (final)\n";
}

1 Ответ

0 голосов
/ 23 июня 2019

Так как #define bit_mask(size, offset) (~((unsigned long long)~0 << size) << offset) похоже, что это решило проблему, я отмечу это как ответ. Если кто-нибудь сообщит, что это не было правильным решением, и он предоставит что-то другое, я приму его ответ, при условии, что он работает.

...