Безопасно ли использовать -1 для установки всех битов в истинное значение?

132

Я видел, как этот шаблон часто используется в C и C ++.

unsigned int flags = -1;  // all bits are true

Это хороший портативный способ сделать это? Или пользуется 0xffffffffили ~0лучше?

hyperlogic
источник
1
Я не понимаю, не могли бы вы объяснить?
corazza
8
Я думаю, ясен ли смысл кода - это самый важный вопрос. Несмотря на то, -1что всегда будет работать, тот факт, что после него нужен комментарий, показывает, что это нечеткий код. Если переменная должна быть набором флагов, зачем присваивать ей целое число? Его тип может быть целым числом, но определенно семантически не целым. Вы никогда не будете увеличивать или умножать его. Поэтому я бы использовал 0xffffffffне для мобильности или правильности, но для ясности.
Кэм Джексон
@CamJackson комментария нет, и любой, кто пишет код C, может быть знаком с тем, как представлены значения.
Miles Rout
Первоначально вопрос был правильно помечен как C и C ++. Языки могут расходиться в том, что C ++ предлагает два дополнения. Тем не менее, это не меняет того факта, что -1остается переносимым и обратно совместимым решением для обоих языков, но это может повлиять на некоторые рассуждения в других ответах.
Адриан Маккарти

Ответы:

154

Я рекомендую вам делать это именно так, как вы показали, так как это наиболее простой способ. Инициализировать, -1который будет работать всегда , независимо от фактического представления знака, но ~иногда будет иметь удивительное поведение, потому что вам потребуется правильный тип операнда. Только тогда вы получите самое высокое значение unsignedтипа.

В качестве примера возможного сюрприза рассмотрим этот:

unsigned long a = ~0u;

Он не обязательно сохранит шаблон со всеми битами 1 a. Но сначала он создаст шаблон со всеми битами 1 в элементе unsigned int, а затем назначит его a. Что происходит, когда unsigned longбитов больше, так это то, что не все из них равны 1.

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

unsigned int a = ~0; // Should have done ~0u !

Причина в том, что ~0нужно инвертировать все биты. Инвертирование, которое даст результат -1на машине с дополнением до двух (что нам и нужно!), Но не даст результата -1на другом представлении. На машине с дополнением до единицы это дает ноль. Таким образом, на машине с дополнением до единицы указанное выше будет инициализировано aнулем.

Вы должны понимать, что все дело в значениях, а не в битах. Переменная инициализируется значением . Если в инициализаторе вы измените биты переменной, используемой для инициализации, значение будет сгенерировано в соответствии с этими битами. Значение, необходимое для инициализации aмаксимально возможным значением, - это -1или UINT_MAX. Второй будет зависеть от типа a- вам нужно будет использовать ULONG_MAXдля unsigned long. Однако первый не будет зависеть от его типа, и это хороший способ получить наибольшее значение.

Мы не говорим о том -1, все ли биты равны единице (не всегда). И мы не говорим о том ~0, все ли биты едины (конечно, есть).

Но мы говорим о том, каков результат инициализированной flagsпеременной. И для этого, только-1 будет работать с каждым типом и машиной.

Йоханнес Шауб - Литб
источник
9
почему -1 гарантированно конвертируется во все единицы? Это гарантируется стандартом?
jalf
9
происходит преобразование: он многократно добавляет на единицу больше, чем ULONG_MAX, пока он не окажется в диапазоне (6.3.1.3 в черновике C TC2). В C ++ это то же самое, просто используется другой способ формализации (по модулю 2 ^ n). Все сводится к математическим отношениям.
Йоханнес Шауб - лит,
6
@litb: приведение -1 - это, безусловно, хороший способ получить максимальные беззнаковые значения, но не совсем описательный; по этой причине существуют константы _MAX (SIZE_MAX был добавлен в C99); конечно, версия на C ++ numeric_limits<size_t>::max()немного многословна, но и актерский состав тоже ...
Кристоф
11
«Мы не говорим о том, все ли биты у -1 равны единице (это не всегда есть). И мы не говорим о том, есть ли у ~ 0 все биты единица (конечно же)». - Что ??? Я думал , что все дело было установить все биты в 1. Вот как флаги work..no ?? Вы смотрите на биты . Кого волнует стоимость?
mpen 01
14
@ Отметьте, что спрашивающий заботится. Он спрашивает: «Безопасно ли использовать -1 для установки всех битов в истину». Это не спрашивает, какие биты -1представлены, и не спрашивает, какие биты ~0есть. Нас могут не волновать значения, но компилятор заботится. Мы не можем игнорировать тот факт, что операции работают со значениями и по ним. Значение из ~0не может быть -1, но это значение вам нужно. См. Мой ответ и резюме @Dingo.
Йоханнес Шауб - литб,
49
  • unsigned int flags = -1; портативный.
  • unsigned int flags = ~0; не переносится, потому что он полагается на представление с дополнением до двух.
  • unsigned int flags = 0xffffffff; не переносится, потому что предполагает 32-битные целые числа.

Если вы хотите установить все биты способом, гарантированным стандартом C, используйте первый.

Динго
источник
10
Как ~ 0 (т.е. оператор дополнения до единицы) полагается на представление дополнения до двух?
Дрю Холл,
11
У вас есть это задом наперед. Его флаг установки в -1, который полагается на представление дополнения до двух. В представлении знак + величина минус один имеет только два установленных бита: бит знака и младший бит величины.
Стивен С. Стил,
15
Стандарт C требует, чтобы нулевое значение int имело знаковый бит, а все биты значения были равны нулю. После дополнения до единицы все эти биты становятся одним целым. Значения int со всеми установленными битами: Знак и величина: INT_MIN Дополнение до одного: -0 Дополнение до двух: -1 Итак, утверждение «unsigned int flags = ~ 0;» присвоит любое значение, указанное выше, соответствует целочисленному представлению платформы. Но дополнение «-1» до двух - единственное, которое установит все биты флагов в единицу.
Динго
9
@ Стивен: Согласен с представлением. Но когда значение int присваивается unsigned int, unsigned не получает своего значения, принимая внутреннее представление значения int (за исключением систем с двумя дополнениями, где это обычно работает). Все значения, присвоенные беззнаковым int, являются модулем (UINT_MAX + 1), поэтому присвоение -1 работает независимо от внутреннего представления.
Динго
20
@Mark: вы путаете две операции. конечно ~0дает intзначение со всеми установленными битами. Но присвоение intan unsigned intне обязательно приводит к тому, что unsigned int имеет тот же битовый шаблон, что и знаковый битовый шаблон. Это всегда имеет место только в случае представления с дополнением до 2. В представлении с дополнением до единиц или знаковой величины присвоение отрицательного intзначения unsigned intрезультату в другом битовом шаблоне. Это связано с тем, что стандарт C ++ определяет преобразование со знаком -> без знака как значение, равное по модулю, а не значение с теми же битами.
Стив Джессоп,
25

Честно говоря, я думаю, что все fff более читабельны. Что касается комментария о том, что это антипаттерн, если вам действительно важно, чтобы все биты были установлены / очищены, я бы сказал, что вы, вероятно, находитесь в ситуации, когда вы все равно заботитесь о размере переменной, что потребовало бы чего-то вроде повышения :: uint16_t и т. д.

Дуг Т.
источник
Есть ряд случаев, когда вам все равно, но они редки. Например, алгоритмы, которые работают с наборами данных из N бит, разбивая их на фрагменты размером (без знака) * CHAR_BIT бит каждый.
MSalters
2
+1. Даже если размер типа данных больше, чем количество F (т. Е. Вы не совсем установили все биты в true), поскольку вы явно устанавливаете значение, вы, по крайней мере, знаете, какие биты являются «безопасными». to use "..
mpen 01
17

Способ, позволяющий избежать упомянутых проблем, - это просто сделать:

unsigned int flags = 0;
flags = ~flags;

Портативный и в точку.

Хаммар
источник
2
Но тогда вы теряете способность декларировать flagsкак const.
Дэвид Стоун
1
@DavidStoneunsigned int const flags = ~0u;
@Zoidberg '- это не работает в системах, кроме двух дополнений. Например, в системе регистрации величины, ~0представляет собой целое число , которое имеет все биты , установленные в 1, но когда вы затем присвоить , что intк unsignedпеременной flags, необходимо выполнить преобразование значения из -2**31(предполагая , что 32-бит int) , чтобы (-2**31 % 2**32) == 2**31, который является целым числом со всеми битами, кроме первого, установлено 1.
Дэвид Стоун
Это также причина, почему этот ответ опасен. Кажется, что ответ @Zoidberg будет идентичным, но на самом деле это не так. Однако, как человек, читающий код, я должен подумать об этом, чтобы понять, почему вы предприняли два шага для его инициализации и, возможно, испытываете соблазн изменить это на один шаг.
Дэвид Стоун
2
Ах да, я не заметил uсуффикс в вашем ответе. Это, конечно, сработает, но по-прежнему существует проблема с указанием типа данных, который вы используете ( unsignedи не больше) дважды, что может привести к ошибкам. Однако ошибка, скорее всего, появится, если назначение и объявление начальной переменной находятся дальше друг от друга.
Дэвид Стоун
13

Я не уверен, что использование unsigned int для флагов является хорошей идеей в первую очередь для C ++. А как насчет битсета и тому подобного?

std::numeric_limit<unsigned int>::max()лучше, потому что 0xffffffffпредполагает, что unsigned int является 32-битным целым числом.

Эдуард А.
источник
Мне это нравится из-за его стандарта, но он слишком многословен и заставляет указывать тип дважды. Использование ~ 0, вероятно, безопаснее, поскольку 0 может быть любым целочисленным типом. (Хотя я знаю, что он слишком сильно пахнет C.)
Macke
То, что он многословен, можно рассматривать как преимущество. Но мне тоже нравится ~ 0.
Эдуард А.
2
Вы можете уменьшить многословность с помощью стандартного макроса UINT_MAX, поскольку вы в любом случае жестко кодируете тип unsigned int.
2
@Macke Вы можете избежать указания типа в C ++ 11 с помощью auto. auto const flags = std::numeric_limit<unsigned>::max(),
Дэвид Стоун
11
unsigned int flags = -1;  // all bits are true

"Это хороший [,] портативный способ сделать это?"

Портативный? Да .

Хорошо? Спорный , о чем свидетельствует вся путаница, показанная в этой ветке. Достаточная ясность, чтобы ваши товарищи-программисты могли понять код без путаницы, должна быть одним из критериев, которые мы измеряем для хорошего кода.

Кроме того, этот метод подвержен предупреждениям компилятора . Чтобы обойти предупреждение без ущерба для вашего компилятора, вам потребуется явное приведение. Например,

unsigned int flags = static_cast<unsigned int>(-1);

Явное приведение требует, чтобы вы обращали внимание на целевой тип. Если вы обращаете внимание на тип цели, то, естественно, вы избежите ошибок других подходов.

Я бы посоветовал обратить внимание на целевой тип и убедиться, что нет неявных преобразований. Например:

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

Все это правильно и более очевидно для ваших коллег-программистов.

И с C ++ 11 : мы можем использовать, autoчтобы сделать любое из этих действий еще проще:

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);

Я считаю правильное и очевидное лучше, чем просто правильное.

Адриан Маккарти
источник
10

Стандарт гарантирует преобразование -1 в любой беззнаковый тип как все-единицы. Использование, ~0Uкак правило, плохо, поскольку 0имеет тип unsigned intи не будет заполнять все биты большего беззнакового типа, если вы явно не напишете что-то вроде ~0ULL. В нормальных системах он ~0должен быть идентичен -1, но поскольку стандарт допускает представления с дополнением до единицы и знаком / величиной, строго говоря, он не переносится.

Конечно, всегда нормально писать, 0xffffffffесли вы знаете, что вам нужно ровно 32 бита, но -1 имеет то преимущество, что он будет работать в любом контексте, даже если вы не знаете размер типа, например макросы, которые работают с несколькими типами , или если размер типа зависит от реализации. Если вы знаете тип, другой безопасный способ , чтобы получить все-онов есть предел макросов UINT_MAX, ULONG_MAX, ULLONG_MAXи т.д.

Лично я всегда использую -1. Это всегда работает, и вам не нужно об этом думать.

R .. GitHub ОСТАНОВИТЬ, ПОМОГАЯ ЛЕД
источник
FWIW, если я имею в виду «все 1 бит», я использую ~(type)0(ну, заполните справа, typeконечно). Приведение к нулю по-прежнему приводит к нулю, так что это ясно, а отрицание всех битов в целевом типе довольно четко определено. Однако не так часто мне действительно нужна эта операция; YMMV.
Donal Fellows
6
@ Донал: вы просто не правы. C указывает, что при преобразовании значения, которое не вписывается в беззнаковый тип, значения уменьшаются по модулю 2 ^ n, где n - количество битов в целевом типе. Это применимо как к знаковым значениям, так и к большим беззнаковым типам. Это не имеет ничего общего с дополнением до двоек.
R .. GitHub НЕ ПОМОГАЕТ ICE
2
Они действительно реализуют это так же, что тривиально; вы просто используете беззнаковый код операции вычитания вместо подписанного или negинструкции. Машины, которые имеют фиктивное арифметическое поведение со знаком, имеют отдельные арифметические коды операций со знаком / без знака. Конечно, действительно хороший компилятор всегда будет игнорировать подписанные коды операций даже для подписанных значений и, таким образом, получит бесплатное дополнение до двух.
R .. GitHub ОСТАНОВИТЬ ПОМОЩЬ ЛЬДУ
1
@R .: Регистр var = ~(0*var)не будет varиметь значения, если тип без знака уже int. Возможно var = ~(0U*var)? ( -1хотя лично я все еще предпочитаю ).
caf
1
Этот ответ намного яснее, чем ответ Йоханнеса Шауба. Однако присвоение целого отрицательного литерала целому типу без знака без приведения обычно приводит к предупреждению компилятора. Для подавления предупреждения требуется приведение, что означает, что в любом случае необходимо обращать внимание на целевой тип, поэтому вы также можете использовать UINT_MAX или ULONG_MAX и быть ясным, а не полагаться на крошечные детали в стандарте, что явно сбивает с толку многих ваших коллег-программистов ,
Адриан Маккарти
5

Пока у вас есть #include <limits.h>один из ваших включений, вы должны просто использовать

unsigned int flags = UINT_MAX;

Если вам нужно много битов, вы можете использовать

unsigned long flags = ULONG_MAX;

Эти значения гарантированно будут иметь все биты значений результата, равные 1, независимо от того, как реализованы целые числа со знаком.

Майкл Норриш
источник
1
предложенные вами константы фактически определены в limits.h - stdint.h содержит ограничения для дополнительных типов целых чисел (целые числа фиксированного размера, intptr_t, ...)
Кристоф
5

Да. Как упоминалось в других ответах, -1это самый портативный; однако он не очень семантичен и вызывает предупреждения компилятора.

Чтобы решить эти проблемы, попробуйте этот простой помощник:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

Использование:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;
Алмазный питон
источник
3
Мне, программисту на C, снятся кошмары по ночам.
jforberg
И что происходит, когда вы используете это в контексте, например, ALL_BITS_TRUE ^ aгде aцелое число со знаком? Тип остается целым числом со знаком, а битовый шаблон (представление объекта) зависит от того, является ли цель дополнением до 2 или нет.
Питер Кордес
Нет, ALL_BITS_TRUE ^ aвыдает ошибку компиляции, потому что ALL_BITS_TRUEнеоднозначно. Однако его можно использовать как uint32_t(ALL_BITS_TRUE) ^ a. Вы можете попробовать сами на cpp.sh :) В настоящее время я бы добавить static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");в , operatorчтобы быть уверенным , пользователи не пытаются использовать int(ALL_BITS_TRUE). Я обновлю ответ.
Diamond Python
3

Я бы не стал делать -1. Это довольно неинтуитивно (по крайней мере, для меня). Присвоение подписанных данных беззнаковой переменной кажется нарушением естественного порядка вещей.

В вашей ситуации я всегда использую 0xFFFF. (Конечно, используйте правильное количество F для переменного размера.)

[Кстати, я очень редко вижу трюк с -1 в реальном коде.]

Кроме того, если вы действительно заботитесь об отдельных битов в vairable, было бы хорошей идеей , чтобы начать работу с фиксированной шириной uint8_t, uint16_t, uint32_tтипы.

Мирон-semack
источник
2

На процессорах Intel IA-32 нормально записать 0xFFFFFFFF в 64-битный регистр и получить ожидаемые результаты. Это связано с тем, что IA32e (64-битное расширение IA32) поддерживает только 32-битные немедленные. В 64-битных инструкциях 32-битные непосредственные символы расширяются до 64- битных .

Следующее является незаконным:

mov rax, 0ffffffffffffffffh

Следующее помещает 64 единицы в RAX:

mov rax, 0ffffffffh

Для полноты изложения в нижнюю часть RAX (также известного как EAX) помещается 32 единицы:

mov eax, 0ffffffffh

И на самом деле у меня случались сбои программ, когда я хотел записать 0xffffffff в 64-битную переменную, и вместо этого я получил 0xffffffffffffffff. В C это будет:

uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);

результат:

x is 0xffffffffffffffff

Я подумал опубликовать это как комментарий ко всем ответам, в которых говорилось, что 0xFFFFFFFF предполагает 32 бита, но так много людей ответили на него, я решил, что добавлю его как отдельный ответ.

Натан Феллман
источник
1
Поздравляем, вы нашли ошибку компилятора!
тк.
Это было задокументировано как ошибка?
Натан Феллман
1
Предполагая, что UINT64_C(0xffffffff)расширяется до чего-то вроде 0xffffffffuLL, это определенно ошибка компилятора. Стандарт C в основном обсуждает значения , значение, представленное равным 0xffffffff4294967295 (а не 36893488147419103231), и никаких преобразований в целочисленные типы со знаком не видно.
тк.
2

См. Ответ Литба для очень четкого объяснения проблем.

Я не согласен с тем, что, строго говоря, нет никаких гарантий ни в том, ни в другом случае. Я не знаю ни одной архитектуры, которая не представляла бы беззнаковое значение `` на единицу меньше двух в степени числа битов '', когда все биты установлены, но вот что на самом деле говорит Стандарт (3.9.1 / 7 плюс примечание 44):

Представления целочисленных типов должны определять значения с использованием чистой двоичной системы счисления. [Примечание 44:] Позиционное представление для целых чисел, использующее двоичные цифры 0 и 1, в котором значения, представленные последовательными битами, являются аддитивными, начинаются с 1 и умножаются на последовательную интегральную степень 2, за исключением, возможно, бита с самая высокая позиция.

Это оставляет возможность для одного из битов быть чем-либо вообще.

Джеймс Хопкин
источник
В общем, мы не можем быть уверены в значении битов заполнения. И если мы захотим, то мы можем оказаться в опасности, так как мы можем сгенерировать для них представление ловушки (и это может вызвать сигналы). Однако std требует, чтобы unsigned char не имел битов заполнения, а в 4.7 / 2 в стандарте С ++ говорится, что преобразование целого числа в беззнаковый тип значение результирующей беззнаковой переменной является наименьшим значением, совпадающим с исходным целочисленным значением, (по модулю 2 ^ n, n == количество бит в беззнаковом типе). тогда (-1) == ((2 ^ n) -1) (mod 2 ^ n). 2 ^ n-1 имеет все биты, установленные в чисто двоичной системе счисления.
Йоханнес Шауб - лит,
Если мы действительно хотим иметь все биты 1 в объектном представлении беззнакового типа, нам понадобится memset. Но мы могли бы сгенерировать таким образом представление ловушки :( В любом случае, у реализации, вероятно, нет причин отбрасывать немного своих целых чисел без знака, чтобы использовать их для хранения своих значений. Но у вас есть очень хороший момент - ничто не останавливает интерпретация из наличия нескольких глупых бредов, я думаю (кроме char / signed char / unsigned char, которые не должны иметь их). +1, конечно :)
Йоханнес Шауб - litb
В конце концов, я думаю, что стандарт мог бы быть более ясным, к какому представлению он относится в 4.7 / 2. Если это относится к представлению объекта, то больше нет места для битов заполнения (я видел, как люди спорят так, в чем я не вижу ничего плохого). Но я думаю, что здесь говорится о представлении значения (потому что все в 4.7 / 2 в любом случае относится к значениям - и тогда биты заполнения могут располагаться рядом с битами значений.
Йоханнес Шауб - litb
1
Стандарт, кажется, довольно ясно имеет в виду представления «2 дополнения, 1 и знаковой величины», но не хочет ничего исключать. Интересный момент насчет ловушек представлений тоже. Насколько я могу судить, процитированный мною бит является определением `` чистой двоичной системы счисления '' в том, что касается Стандарта - бит `` кроме '' в конце действительно является моим единственным сомнением в том, что приведение -1 гарантированно работай.
Джеймс Хопкин
2

Хотя 0xFFFF(или 0xFFFFFFFFи т. Д.) Может быть легче читать, это может нарушить переносимость кода, который в противном случае был бы переносимым. Рассмотрим, например, библиотечную подпрограмму для подсчета количества элементов в структуре данных, для которых установлены определенные биты (точные биты указываются вызывающей стороной). Процедура может быть полностью независимой от того, что представляют собой биты, но все же должна иметь константу «все биты установлены». В таком случае -1 будет намного лучше, чем шестнадцатеричная константа, поскольку она будет работать с любым размером бит.

Другая возможность, если typedefдля битовой маски используется значение, - это использовать ~ (bitMaskType) 0; если битовая маска имеет только 16-битный тип, в этом выражении будет установлено только 16 бит (даже если int в противном случае будет 32 бита), но поскольку все, что требуется, будет 16 бит, все должно быть в порядке при условии, что один фактически использует соответствующий тип при приведении типов.

Между прочим, у выражений формы longvar &= ~[hex_constant]есть неприятная ошибка, если шестнадцатеричная константа слишком велика, чтобы поместиться в int, но она уместится в unsigned int. Если an int- 16 бит, то longvar &= ~0x4000;или longvar &= ~0x10000; очистит один бит longvar, но longvar &= ~0x8000;очистит бит 15 и все биты выше этого. Подходящие значения intбудут иметь оператор дополнения, примененный к типу int, но результат будет расширен знаком long, установив старшие биты. Для слишком больших значений unsigned intбудет применяться оператор дополнения к типу long. Однако значения, находящиеся между этими размерами, будут применять оператор дополнения к типу unsigned int, который затем будет преобразован в тип longбез расширения знака.

Supercat
источник
1

Практически: да

Теоретически: Нет.

-1 = 0xFFFFFFFF (или любой другой размер int на вашей платформе) верно только с двумя арифметическими дополнениями. На практике это будет работать, но существуют устаревшие машины (мэйнфреймы IBM и т. Д.), На которых у вас есть фактический знаковый бит, а не представление с дополнением до двух. Предлагаемое вами решение ~ 0 должно работать везде.

Дрю Холл
источник
6
Я тоже это сказал. Но потом я понял, что ошибался, поскольку знак -1 всегда преобразуется в max_value unsigned согласно правилам преобразования, независимо от представления значений. По крайней мере, в C ++, у меня под рукой нет стандарта C.
Стив Джессоп,
6
есть двусмысленность. -1 не является 0xFFFFFFFF. Но -1 равно 0xFFFFFFFF, если преобразовано в беззнаковое int (имеющее 32 бита). Я думаю, именно это и делает эту дискуссию такой сложной. Многие люди имеют в виду совершенно разные вещи, когда говорят об этих битовых строках.
Йоханнес Шауб - лит,
1

Как уже упоминалось, -1 - это правильный способ создать целое число, которое будет преобразовано в беззнаковый тип со всеми битами, установленными в 1. Однако самая важная вещь в C ++ - это использование правильных типов. Следовательно, правильный ответ на вашу проблему (который включает ответ на заданный вами вопрос) таков:

std::bitset<32> const flags(-1);

Он всегда будет содержать точное количество битов, которые вам нужны. Он создает a std::bitsetсо всеми битами, установленными в 1 по тем же причинам, которые упоминались в других ответах.

Дэвид Стоун
источник
0

Это, конечно, безопасно, так как -1 всегда будет иметь все доступные биты, но мне больше нравится ~ 0. -1 просто не имеет особого смысла для unsigned int. 0xFF... нехорошо, потому что это зависит от ширины шрифта.

Zifre
источник
4
«0xFF ... нехорошо, потому что это зависит от ширины типа». Я думаю, это единственный разумный способ. Вы должны четко определить, что означает каждый флаг / бит в вашей программе. Итак, если вы определяете, что используете самые низкие 32 бита для хранения флагов, вы должны ограничить себя использованием этих 32 бита, независимо от того, является ли фактический размер int 32 или 64.
Хуан Пабло Калифано
0

Я говорю:

int x;
memset(&x, 0xFF, sizeof(int));

Это всегда даст желаемый результат.

Alex
источник
4
Не в системах с 9-битными символами!
тк.
0

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

Назначение -1 работ для любого знака целого типа (без знака Int, uint8_t, uint16_t и т.д.) для обоих C и C ++.

В качестве альтернативы для C ++ вы можете:

  1. Включите <limits>и используйтеstd::numeric_limits< your_type >::max()
  2. Напишите пользовательскую шаблонную функцию (это также позволило бы провести некоторую проверку работоспособности , т. Е. Если тип назначения действительно является неподписанным типом)

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

Антонио
источник
0

Способ сделать значение более очевидным и при этом избежать повторения типа:

const auto flags = static_cast<unsigned int>(-1);
FlorianH
источник
-6

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

например, на большинстве машин целое число составляет 2 байта = 16 бит, максимальное значение, которое оно может содержать, равно 2 ^ 16-1 = 65535 2 ^ 16 = 65536

0% 65536 = 0-1% 65536 = 65535, что соответствует 1111 ............. 1, и все биты установлены в 1 (если мы рассматриваем классы остатка по модулю 65536), следовательно, это много прямо вперед.

я думаю

нет, если вы рассматриваете это понятие, оно идеально подходит для неподписанных целых, и это действительно работает

просто проверьте следующий фрагмент программы

int main () {

unsigned int a=2;

cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));

unsigned int b=-1;

cout<<"\n"<<b;

getchar();

return 0;

}

ответ для b = 4294967295, который равен -1% 2 ^ 32 для 4-байтовых целых чисел

следовательно, это совершенно верно для целых чисел без знака

в случае каких-либо неточностей сообщите пожалуйста

Анкит Саблок
источник
9
Два комментария: во-первых, вы ошибаетесь насчет размера целых чисел на «большинстве» машин. Во-вторых, ur txt из-за очень трудного чтения 2 из-за того, что мы говорим о сумасшедшем языке. Plz нам простой английский .
Конрад Рудольф