LINUX.ORG.RU

unsigned long long = -1

 


2

4

Здравствуйте, я не могу понять - валидна ли такая конструкция:

#include <iostream>
using namespace std;
int main() {
   int i = -1;
   unsigned long long ull = i;
   
   unsigned long long ull_2 = 0;
   -- ull_2;
   if(ull != ull_2)
      cout << "not equal\n"; // не печатается
}
Даже не то чтобы валидна (она такова), а является ли ожидаемый результат (ull == ULLONG_MAX) грантированным стандартом? Бегло пробежался по докам, самое подходящее из того, что нашёл

4.8 Integral conversions [conv.integral]
1 ...
2
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type). [Note:In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note]

Может неправильно понимаю, но что-то вроде - взять беззнаковый тип, который достаточен для первоначально знакового целового. Т.е. sizeof(Integral_conversions(i)) == 4, а мне нужна конвертация в sizeof(Integral_conversions(i)) == 8. Т.е. очевидно, что есть разница между int->unsigned int->unsigned long long и int->unsigned long long. Запись unsigned long long ull = (unsigned long long)i не рассматриваем.

★★

Ответ на: комментарий от RazrFalcon

Я знаю про signed integer overflow - это ЮБ, а про unsigned integer overflow никогда не слышал (поиск по стандарту так же не даёт результата), у беззнаковые можно переполнять.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

имелось, наверное в виду

int i = -1; 
вот тебе и UB UPD: хотя чо это я сморозил лол...

можно например

unsigned long long invalid = std::numeric_limits<unsigned long long>::max();

jeuta ★★★★
()
Последнее исправление: jeuta (всего исправлений: 1)

Нет там никакого UB. Написано же русским языком, что если значение не помещается в новый беззнаковый тип, то к значению, в случае отрицательных величин, прибавляется (1+NEW_TYPE_MAX) до тех пор, пока значение не влезет, либо же, в случае положительных величин вычитается тоже самое значение. То есть, если мы пытаемся запихать -2 в unsigned char, то новое значение будет -2 + (1+255) = 254. А если мы в тот же тип попытаемся затолкать 257, то новое значение будет 257 - (1+255) = 1.

anonymous
()
Ответ на: комментарий от RazrFalcon

unsigned integer overflow

3.9.1 Fundamental types [basic.fundamental]
4 Unsigned integers shall obey the laws of arithmetic modulo 2ⁿ where n is the number of bits in the value representation of that particular size of integer.⁴⁸

48) This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.

utf8nowhere ★★★
()

Спасибо за ответы. Но вопрос не о наличии ЮБ (его там нет, я сразу написал), а о способе коневертации (тут по-разному можно), например:
unsigned long long ull = -1;
ull == 8 байт, -1 == 4 байта. ull == unsigned, -1 == signed
Грубо можно разделить процесс присваивания на две стадии: приведение знаковости и приведение размера операндов к общему. Следовательно, появляются две возможности:
1. int'ый -1 кастуем в знаковый long long, а потом кастуем в unsigned long long. ull = (unsigned long long)-1(long long)
2. int'ый -1 кастуем в unsigned int, а потом кастуем в unsigned long long. ull = (unsigned long long)-1(unsigned int)
Два пути дают абсолютно разный результат. Где/чем/кем гарантируется какой-то из двух возможный вариантов?

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Следовательно, появляются две возможности:

Возможность одна: int -> unsigned long long. По правилу, описанному в 4.7 paragpraph 2.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Вы про это?

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type). [Note:In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note]

Вначале писал:

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

Какой беззнаковый тип достаточен для хранения -1? Очевидно, что unsigned int, с чего это вдруг может понадобиться кастовать к unsigned long long? int в состоянии сохранить значение.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Какой беззнаковый тип достаточен для хранения -1?

unsigned char. unsigned short. Смотря к чему присваиваешь.

с чего это вдруг может понадобиться кастовать к unsigned long long?

С того, что ты ему присваиваешь.

Ты, видимо, не можешь осознать, что в

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer

вычисление the resulting value происходит в кагбэ «честных» целых числах. Бесконечных в обе стороны. К source integer прибавляется или отнимается (1+DESTINATION_TYPE_MAX) и при этом тип как source integer, так и (1+DESTINATION_TYPE_MAX) не является ни source, ни destination типом, а является «честным» целым числом.

utf8nowhere ★★★
()
Ответ на: комментарий от pavlick

Какой беззнаковый тип достаточен для хранения -1?

Ну и, вообще говоря, никакой, т.к. беззнаковый не может хранить отрицательные числа. :P

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

вычисление the resulting value происходит в кагбэ «честных» целых числах

Для этого есть термин: m-адическое число.

Norgat ★★★★★
()

Я не могу сказать, что вопрос исчерпан, для меня не всё ясно. Одно предложение из стандарта, и интерпретируй как нравится. Ну да ладно, хрен с ним, работает как ожидается.

Но правильно ли я понимаю, что такая инициализация может дать не UINT_MAX на one's complement machine?

unsigned = -1;
Т.е. чисто теоретически, такая техника не очень правильна.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Ну например если умный компилятор отбросит бит знаковости при приведении типа, то будет 1. Насколько это вероятно?

anonymous
()
Ответ на: комментарий от pavlick

А. Я тебя сразу, асмодауна, не опознал. Это ты «баги» в поведении volatile находишь. Лалка.

Неудивительно, что ты таких простых вещей не понимаешь.

anonymous
()
Ответ на: комментарий от pavlick

Т.е. чисто теоретически, такая техника не очень правильна.

Вот тут уже десяток постов написали пытаясь понять что должно получиться в итоге. Конечно такая техника неправильна. Уже потому, что читающему код не очевидно что задумывал автор. Нужно сначала писать понятный код, а потом уже оптимизировать его используя разные трюки.

asaw ★★★★★
()
Ответ на: комментарий от anonymous

На самом деле тут стоит подумать не про компилятор, а про оптимизатор. Зачем вообще писать такое дерьмо?

anonymous
()
Ответ на: комментарий от asaw

Вот тут уже десяток постов написали пытаясь понять что должно получиться в итоге.

Ах...еть, это так трудно понять, что одно и то-же «физическое представление» в зависимости от типа даёт два значения?! А весь «спич» в доке - попытка это описать не опускаясь до железа?

yyk ★★★★★
()
Ответ на: комментарий от yyk

Я не знаю что тебя так возмущает, но все релевантные цитаты уже преведены. Первую привёл ТС в самом начале, вторую можно суммировать вот так:

Overflows

Unsigned integer arithmetic is always performed modulo 2^n where n is the number of bits in that particular integer. E.g. for unsigned int, adding one to UINT_MAX gives ​0​, and subtracting one from ​0​ gives UINT_MAX.

When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined: it may wrap around according to the rules of the representation (typically 2's complement), it may trap on some platforms or due to compiler options (e.g. -ftrapv in GCC and Clang), or may be completely optimized out by the compiler.

И при этом не всем всё очевидно. Значит нужно писать std::numeric_limits<unsigned long long>::max(); и т.д.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 2)

(modulo 2^n where n is the number of bits used to represent the unsigned type).

Оказывается modulo - это остаток от целочисленного деления, не знал. Тогда это вообще о другом - о том, что unsigned можно спокойно переполнять, а signed нет. Но ни слова о том, что сначала - приведение размера или знака. ull = (unsigned long long)-1(long long) ИЛИ ull = (unsigned long long)-1(unsigned int).

int i = -1;
unsigned long long ull = i;
ull = i % 2^sizeof(unsigned long long);

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от pavlick

Об этом написано цитате, которую привёл ты сам в первом посте.

asaw ★★★★★
()

По сути ситуация в топике — UB. Однако в силу двух аспектов она будет работать как описано в топике:

  1. Машинное представление знаковых типов: сейчас наиболее часто встречается two's complement («дополнительный код»). Вот тут больше: https://en.wikipedia.org/wiki/Signed_number_representations
  2. Sign extension. Для увеличения количества бит целого числа самый значимый бит просто «растягуется» до нужной ширины

В данном случае (int)-1 в обратном коде представляется как число из битовых единиц (для 2 байт: 1111 1111 1111 1111b). Поскольку sizeof(int) < sizeof(unsigned long long), int нужно «растянуть». Соответственно, «растягивание» старшего бита будет давать число из битовых единиц. При конвертиновании в unsigned такое число будет естественно максимальным значением для данного unsigned типа.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 3)
Ответ на: комментарий от KennyMinigun

Sign extension. Для увеличения количества бит целого числа самый значимый бит просто «растягуется» до нужной ширины

Я хотел найти подтвержение этому в стандарте (т.е. сначала увеличивается наша интовая -1 до нужного знакого типа (long long int в нашем случае), а потом делаем её беззнаковой). Но странно, стандарт ничего не обещает (не нашёл).

ЗЫ: возможно заморачиваюсь слишком )).

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от pavlick

Ты просто элементарно не умеешь читать по-английски, всё остальное тут ни при чём.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от pavlick

вообще signed от unsigned отличаются только способом проверки больше-меньше. в х86 это jl/jle/jg/jge vs jb/jbe/ja/jae и соотв. набор команд set. ну и флаги немного по другому трактуются.

i36_zubov
()
Ответ на: комментарий от Norgat

Если ты мне хочешь сказать что то, что я описал — это арифметика по модулю, то я знаю. Я сознательно не стал это писать, потому что тормоз-ОП понял бы это как арифметику по модулю в C++, где результат при наличии отрицательных операндов implementation-defined.

utf8nowhere ★★★
()
Ответ на: комментарий от pavlick

стандарт ничего не обещает

Он однозначно обещает, что результат будет наименьшим беззнаковым числом, равным по модулю исходному.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

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

Не «равным по модулю исходному», а сравнимым по модулю числа 2^n с исходным. Это не тот модуль, где можно 2^n опустить.

asaw ★★★★★
()
Ответ на: комментарий от asaw

Да, «сравнимым по модулю» говорить правильнее. «Равный по модулю» это про другое.

utf8nowhere ★★★
()
2 мая 2018 г.
Ответ на: комментарий от pavlick

one's complement

Что такое one's complement? Знаю только ones' complement.

anonymous
()

Зачем ты намеренно ищешь приключений на задницу? Есть чёрному по белому спецификатор unsigned тип int, спецификатор signed тип int и так далее, храни в нужное в том что предназначено для этого, можно положить в unsigned long long -1 и даже прочитать printf("%zi",variable); но зачем тебе это UB? Хотя это даже не UB получится, если хочется плясок приводи всё к void * и кастуй к тому что нужно если структура данных позволяет.

Deleted
()

Почему бы не использовать стандартные возможности без UB?:

#include <limits.h>

unsigned           max_uint   = UINT_MAX   ;
unsigned long      max_ulong  = ULONG_MAX  ;
unsigned long long max_ullong = ULLONG_MAX ;

попроще:

unsigned           max_uint   = ~0u   ;
unsigned long      max_ulong  = ~0ul  ;
unsigned long long max_ullong = ~0ull ;
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.