Що станеться, якщо я присвоюю відмінне значення непідписаній змінній?


82

Мені було цікаво дізнатись, що станеться, якщо я призначу негативне значення непідписаній змінній.

Код буде виглядати приблизно так.

unsigned int nVal = 0;
nVal = -5;

Це не дало мені жодної помилки компілятора. Коли я запускав програму, nValїй було присвоєно дивне значення! Чи може бути, що присвоюється значення доповнення деяких 2 nVal?


1
На мою думку (ще не вдалося знайти це в стандарті), поведінка технічно невизначена. Крім того, я підозрюю, що ви побачите те, що очікуєте, майже на будь-якому компіляторі, який ви можете знайти. Тож, хоча ви зазвичай бачите таку поведінку, розраховувати на це, мабуть, не дуже добре.
sblom

6
Він не визначений (див. §4.7 / 2 ), але подання (наприклад, доповнення 2s) не передбачене стандартом.
Георг Фріцше

@gf (та ін. нижче), круто. Схоже, поведінка насправді чітко визначена такою, як ви очікували, @viswanathan.
sblom

3
Другий рядок еквівалентний nVal = (unsigned int) -5;. Акторський -5To unsigned intце визначено в 6.3.1.3. Представлення в додатку 2s не передбачене стандартом, але алгоритм перетворення в беззнаковий: "значення перетворюється шляхом багаторазового додавання або віднімання одного більше максимального значення, яке може бути представлене в новому типі, поки значення не буде в діапазоні нового типу ".
Паскаль Куок,

1
@Pascal: Ви, мабуть, маєте на увазі C99, але питання позначене як C ++.
Георг Фріцше

Відповіді:


67

Офіційну відповідь - розділ 4.7 conv.integral

"Якщо тип призначення без знака, отримане значення є найменш цілим числом без знака, сумісним із цілим числом джерела (за модулем 2 n де nкількість бітів, що використовується для представлення типу без знака). [Примітка. У поданні двох доповнень це перетворення є концептуальним і не змінюється в шаблоні бітів (якщо відсікання немає). — кінцева примітка]

Це, по суті, означає, що якщо основна архітектура зберігає метод, який не є Доповненням Двох (наприклад, Підписана величина або Доповнення Одного), перетворення на беззнакове повинно вести себе так, ніби це Доповнення Двох.


37
Що означає найменш ціле число без знака, яке відповідає цілому числу джерела ?
Девід Родрігес - dribeas

11
@ DavidRodríguez-dribeas Як приклад, 5 і 3 є "конгруентним модом 2", оскільки 5% 2 і 3% 2 є обома.
JoeQuery

До яких версій стандарту C ++ він відноситься? Всі?
Олексій Круглов

36

Він призначить бітовий шаблон, що представляє -5 (у доповненні 2), для беззнакового int. Що буде великим беззнаковим значенням. Для 32-бітових вводів це буде 2 ^ 32 - 5 або 4294967291


2
Біти тут нічого спільного.
GManNickG

1
@BenVoigt: Досить справедливо, я мав на увазі, що це не мало нічого спільного з інтерпретацією бітів. (Тобто, "біти" в цитованій частині - це просто скорочення ceil(log_2(x)).)
GManNickG

1
@GManNickG Біт (як, належить біту)? Комплімент 2 (це дуже приємно з вашого боку) ? ГААААААААААААААХ!
NullUserException

1
@NullUserException: Ха-ха, я знаю. Писати "*" замість просто "*" - це жахлива звичка, яку я мав давно. Що стосується компліменту, а не доповнення, це просто чиста дурість. :)
GManNickG

Простота - головне. Ця відповідь має таке. (2 ^ 32 - 5) пояснює цю поведінку краще, ніж цитування документації.
Редхарт,

4

Це буде відображатись як додатне ціле значення значення max unsigned integer - 4 (значення залежить від архітектури комп'ютера та компілятора).

До речі,
ви можете перевірити це, написавши просту програму типу "Привіт світ" на C ++ і переконайтесь самі


Я написав і перевірив, саме тому я задав питання, але я не знав, як компілятор досяг такого позитивного значення. Дякую
ckv

6
На жаль, у C ++ написання програм для перевірки поведінки не завжди є гарною ідеєю. Наприклад, якщо хтось спробує перевірити, що відбувається у випадку підписаного переповнення, це призведе до невизначеної поведінки, яка не гарантується однаковою на кожній машині / компіляторі.
Бен Джонс,

4

Ви маєте рацію, ціле число з підписом зберігається у формі доповнення 2, а ціле число без підпису зберігається у двійковому поданні без підпису . C (і C ++) не робить різниці між ними, тому значення, яке ви отримаєте, - це просто беззнакове двійкове значення двійкового представлення доповнення 2.


16
Його не можна зберігати в компліменті 2.
GManNickG

Що означає, якщо щось "зберігається у двох?" @GManNickG
JeremyF

4
@JeremyF: Не "2", "2 компліменти". Це термін, який підтримує Google, і спосіб представлення підписаних цілих чисел.
GManNickG

2

Так, ти маєш рацію. Фактичне присвоєне значення приблизно подібне до всіх встановлених бітів, крім третього. -1 - це всі встановлені біти (шістнадцяткове: 0xFFFFFFFF), -2 - усі біти, крім першого тощо. Те, що ви побачите, - це, мабуть, шістнадцяткове значення 0xFFFFFFFB, яке в десятковому значенні відповідає 4294967291.


3
Біти тут нічого спільного, цілочисельне представлення не вказано.
GManNickG

2
Ваша відповідь є правильною, суворою, суттєвою і такою, яку я б ніколи не використовував на уроці.
Мартін

див. мою відповідь щодо доповнення 2 -5. Я не думаю, що ви тут правильно розрахували двійкові значення.
cynistersix

0

Коли ви присвоюєте негативне значення незмінній змінній, тоді він використовує метод доповнення 2, щоб обробити його, і в цьому методі він перевертає всі 0 на 1, а всі 1 на 0, а потім додає 1 до нього. У вашому випадку ви маєте справу з int, який має 4 байти (32 біти), тому він намагається використовувати метод доповнення 2 на 32-бітному номері, що призводить до перекидання верхнього біта. Наприклад:

┌─[student@pc]─[~]
└──╼ $pcalc 0y00000000000000000000000000000101      # 5 in binary
        5                       0x5                     0y101
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010      # flip all bits  
      4294967290      0xfffffffa      0y11111111111111111111111111111010
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 + 1  # add 1 to that flipped binarry
      4294967291      0xfffffffb      0y11111111111111111111111111111011
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.