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


132

Я бачив, як цей зразок багато використовувався в C & C ++.

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

Це хороший портативний спосіб досягти цього? Або використовуєте 0xffffffffчи ~0краще?


1
Я не розумію, поясніть, будь ласка?
corazza

8
Я думаю, чи зрозуміле значення коду - це найважливіше питання. Незважаючи на те -1, що завжди буде працювати, той факт, що коментар потрібен після того, як він покаже, що це не зовсім зрозумілий код. Якщо змінна призначена для набору прапорів, навіщо їй присвоювати ціле число? Його тип може бути цілим числом, але це, звичайно, не семантично ціле число. Ви ніколи не збираєтеся його збільшувати чи примножувати. Тож я б використовував 0xffffffffне для портативності чи коректності, а для ясності.
Cam Jackson

@CamJackson коментар відсутній, і кожен, хто пише код C, може бути знайомий із тим, як представлені значення.
Майлз Рут,

Спочатку питання було належним чином позначено як 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 має всі біти по одному (це не завжди). - кит ??? Я подумав, що вся справа в тому, щоб встановити всі біти на 1. Ось як прапори працюють .. Ти дивишся на шматочки . Хто піклується про цінність?
вересня

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 з усіма встановленими бітами: Sign-and-magnitude: INT_MIN Доповнення одного: -0 Доповнення двох: -1 Отже, вислів "unsigned int flags = ~ 0;" присвоїть значення, яке вище відповідає цілому представленню платформи. Але доповнення '-1' двох є єдиним, яке встановить усі біти прапорців до одного.
Дінго

9
@Stephen: Домовлено про представництво. Але коли значення int присвоюється неподписаному int, непідписаний не отримує свого значення, приймаючи внутрішнє представлення значення int (за винятком двох систем доповнення, де це взагалі працює). Усі значення, призначені для безпідписаних int, є модулем (UINT_MAX + 1), тому присвоєння -1 працює незалежно від внутрішнього представлення.
Дінго

20
@Mark: ви плутаєте дві операції. Звичайно, ~0отримує intзначення з усіма встановленими бітами. Але привласнення intАнь unsigned intНЕ обов'язково призводить до підписаним Int , мають той же бітовий шаблон в якості підписаних біт. Тільки з представленням доповнення 2 це завжди так. На представленні доповнення або знаки величини 1s, присвоєння негативного intзначення unsigned intрезультатам в іншому бітовому малюнку. Це пояснюється тим, що стандарт C ++ визначає перетворене підписане -> непідписане значення, рівне за модулем, а не значення з однаковими бітами.
Стів Джессоп

25

Відверто кажучи, я думаю, що всі FFF-і є читабельнішими. Щодо коментаря, що його антипатерн, якщо вам дійсно все одно, що всі біти встановлені / очищені, я б заперечував, що ви, мабуть, перебуваєте у ситуації, коли ви все одно переймаєтесь розміром змінної, що закликає щось подібне до збільшення :: uint16_t тощо.


Є ряд випадків, коли вас так мало не хвилює, але вони рідкісні. Напр. Алгоритми, які працюють на наборах даних з N бітів, розбиваючи його на шматки розміру (без підпису) * CHAR_BIT біт кожен.
MSalters

2
+1. Навіть якщо розмір типу даних перевищує число F (тобто ви не повністю встановили всі біти на істинне), оскільки ви явно встановлюєте значення, ви принаймні знаєте, які біти "безпечні" скористатися "..
mpen

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

Я не впевнений, що використання непідписаного int для прапорів - це гарна ідея в першу чергу в C ++. Що з бітсетом тощо?

std::numeric_limit<unsigned int>::max()краще, тому що 0xffffffffприпускає, що непідписаний int є 32-бітним цілим числом.


Мені це подобається через його стандарт, але це занадто багатослівно, і це змушує вас вказати тип двічі. Використання ~ 0, ймовірно, безпечніше, оскільки 0 може бути будь-яким цілим числом. (Хоча я знаю, це занадто сильно пахне С.)
Макке

Те, що це багатослівно, можна розглядати як перевагу. Але мені також подобається ~ 0.
Едуард А.

2
Ви можете пом'якшити простоту за допомогою стандартного макросу UINT_MAX, оскільки ви все одно жорстко кодуєте тип без підпису 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. Це завжди працює, і вам не доведеться думати про це.


FWIW, якщо я маю на увазі "всі 1 біт", який я використовую ~(type)0(ну, заповніть справа, typeзвичайно). Закидання нуля все ще призводить до нуля, тому це зрозуміло, а заперечення всіх бітів цільового типу досить чітко визначено. Я не дуже часто хочу, щоб ця операція хоч; YMMV.
Стипендіати Доналу

6
@Donal: ви просто помиляєтесь. C вказує, що при перетворенні значення, яке не вписується в неподписаний тип, значення зменшуються по модулю 2 ^ n, де n - кількість бітів у типі призначення. Це стосується як підписаних значень, так і великих непідписаних типів. Це не має нічого спільного з доповненням двійки.
R .. GitHub СТОП ДОПОМОГАЄТЬСЯ

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
запропоновані вами константи фактично визначені у limit.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. (Використовуйте потрібну кількість Fs для змінного розміру курсу.)

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

Крім того, якщо ви дійсно дбаєте про окремі бітів в vairable, було б гарною ідеєю , щоб почати роботу з фіксованою шириною uint8_t, uint16_t, uint32_tтипи.


2

На процесорах IA-32 від Intel нормально записати 0xFFFFFFFF в 64-розрядний реєстр і отримати очікувані результати. Це відбувається тому, що IA32e (64-розрядне розширення до IA32) підтримує лише 32-бітні прямі. У 64-розрядних інструкціях 32-розрядні безпосередні розширення знаків на 64-бітні.

Наступне незаконне:

mov rax, 0ffffffffffffffffh

Нижче наведено 64 1 в RAX:

mov rax, 0ffffffffh

Для повноти, нижче розміщується 32 1s у нижній частині RAX (він же EAX):

mov eax, 0ffffffffh

Насправді у мене були програми, коли я хотів записати 0xffffffff на 64-бітну змінну, і натомість отримав 0xffffffffffffffffff. У З це було б:

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 вимагає непідписаного символу char, щоб не було бітів прокладки, і в 4.7 / 2 у стандарті c ++ йдеться про те, що для перетворення цілого числа на неподписаний тип значення отриманої неподписаної змінної є найменшим значенням, що відповідає контенту цілого значення джерела, (модуль 2 ^ n, n == число-бітів у непідписаному типі). тоді (-1) == ((2 ^ n) -1) (mod 2 ^ n). 2 ^ n-1 має всі біти, встановлені в чистій двійковій системі нумерації.
Йоханнес Шауб - ліб

Якщо ми дійсно хочемо, щоб усі біти 1 були в об'єктному поданні неподписаного типу, нам знадобиться мемсет. Але ми могли б створити представлення пастки тим самим :( У будь-якому випадку, реалізація, ймовірно, не має підстав відкидати трохи їх непідписаних цілих чисел, тому вона буде використовувати її для зберігання своїх значень. Але у вас дуже хороший момент - нічого не зупиняється інтерпретація від того, що я маю декілька нерозумних нісенітниць, я думаю (окрім char / підписаний char / неподписаний char, який не повинен мати таких). +1 звичайно :)
Йоханнес Шауб - litb

Зрештою, я думаю, що у стандарті може бути зрозуміліше, на яке представлення йдеться у 4.7 / 2. Якщо це стосується представлення об'єкта, то більше немає місця для забивання бітів (я бачив людей, які так сперечаються, з якими я не бачу нічого поганого). Але я думаю, що це говорить про представлення значення (адже все в 4.7 / 2 - це значення в будь-якому випадку - і тоді біт прокладки може гніздитися поруч із бітами значень.
Йоханнес Шауб - ліб

1
Здається, Стандарт звичайно має на увазі доповнення "2", доповнення 1 та підписану величину ", але нічого не хоче виключати. Цікавий момент і щодо захоплення уявлень. Наскільки я можу сказати, біт, який я цитував, - це визначення "чистої двійкової системи числення", що стосується Стандарту, - біт "за винятком" в кінці насправді є моїм єдиним сумнівом щодо того, чи гарантовано кастинг -1 робота.
Джеймс Хопкін

2

Хоча 0xFFFF(або0xFFFFFFFF тощо) може бути легше читати, він може порушити портативність у коді, який інакше був би портативним. Розглянемо, наприклад, процедуру бібліотеки, щоб підрахувати, скільки елементів у структурі даних мають певні біти, встановлені (точні біти визначає абонент). Процедура може бути абсолютно агностичною щодо того, що представляють біти, але все ж потрібно мати постійну "всі біти". У такому випадку -1 буде набагато кращим, ніж шістнадцяткова константа, оскільки він буде працювати з будь-яким розміром бітів.

Іншою можливістю, якщо typedefзначення використовується для бітової маски, було б використовувати ~ (bitMaskType) 0; якщо бітмаска має лише 16-бітний тип, цей вираз матиме лише 16 біт (навіть якщо 'int' інакше буде 32 біта), але оскільки 16 біт буде все необхідне, все повинно бути добре за умови, що один фактично використовує відповідний тип у typecast.

Між іншим, вирази форми 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без розширення знаків.


1

Практично: Так

Теоретично: Ні.

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


6
Я це теж сказав. Але тоді я зрозумів, що я помиляюся, оскільки -1 підписані завжди перетворюються на max_value, не підписані відповідно до правил перетворення, незалежно від представлення значень. Принаймні, це в 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... це не добре, оскільки це залежить від ширини типу.


4
"0xFF ... це не добре, тому що це залежить від ширини типу". Я думаю, це єдиний розумний шлях. Ви повинні чітко визначити, що означає кожен прапор / біт у вашій програмі. Отже, якщо ви визначаєте, що для зберігання прапорів ви використовуєте найнижчі 32 біти, вам слід обмежитися використанням цих 32 біт, незалежно від того, чи дійсний розмір int - 32 чи 64.
Juan Pablo Califano

0

Я кажу:

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

Це завжди дасть бажаний результат.


4
Не в системах з 9-бітовими символами!
тс.

0

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

Призначення -1 працює для будь-якого непідписаного цілого числа (unsigned 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);

-6

так, подане представлення дуже коректно, як якщо б ми це зробили, то навпаки u вимагатиме від оператора повернути всі біти, але в цьому випадку логіка є досить простою, якщо врахувати розмір цілих чисел у машині

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

0% 65536 = 0 -1% 65536 = 65535, котрий похиляється до 1111 ............. 1, а всі біти встановлені на 1 (якщо вважати залишкові класи mod 65536), отже, це набагато прямо вперед.

я вважаю

ні, якщо ви вважаєте це поняття, воно ідеально пообідає для непідписаних ints, і воно справді працює

просто перевірте наступний фрагмент програми

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 байтні цілі числа

отже, це цілком справедливо для непідписаних цілих чисел

у випадку будь-яких невідповідностей, звітуйте про plzz


9
Два коментарі: по-перше, ви помиляєтесь щодо розміру цілих чисел на "більшості" машин. По-друге, ур txt iz дуже важко 2 читати через 2 ур нас суми різновид мови секрета. Plz us звичайна англійська .
Конрад Рудольф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.