Что такое signed и unsigned

Не понимаю разницу между signed / unsigned

На одном из сайтов написано:

The term «unsigned» in computer programming indicates a variable that can hold only positive numbers.

Но ведь я могу сделать так:

Что такое signed и unsigned. Смотреть фото Что такое signed и unsigned. Смотреть картинку Что такое signed и unsigned. Картинка про Что такое signed и unsigned. Фото Что такое signed и unsigned

Что такое signed и unsigned. Смотреть фото Что такое signed и unsigned. Смотреть картинку Что такое signed и unsigned. Картинка про Что такое signed и unsigned. Фото Что такое signed и unsigned

3 ответа 3

TL; DR

Знаковые и беззнаковые типы имеют один и тот же размер, одни и те же требования выравнивания, а отличаются они в основном «смыслом» какого-то одного бита: у первых он означает знак числа, а у вторых — само значение.

Для начала приведу несколько выдержек из стандарта (следует читать по-порядку):

— ISO/IEC 9899:2017 § 6.2.5 / 4

— ISO/IEC 9899:2017 § 6.2.5 / 6

Для любого беззнакового типа (кроме unsigned char ), биты объектного представления делятся на две группы: значимые биты и padding-биты. Если в типе N значимых бит, то он должен быть способен представлять значения от 0 до 2 N − 1 в двоичной системе счисления.

— ISO/IEC 9899:2017 § 6.2.6.2 / 1

Для любого знакового типа биты объектного представления делятся на три группы: значимые биты, padding-биты и знаковый бит. В любом типе должен быть всего один знаковый бит. Если он равен нулю, то результирующее значение не меняется. Если же он равен единице, значение должно быть модифицированно одним из следующих способов:

— ISO/IEC 9899:2017 § 6.2.6.2 / 2

Таким образом отличие знаковых типов от беззнаковых заключается, собственно, в бите знака: в первых он есть, а во вторых — нет.

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

Мы можем присвоить вещественное число переменной типа int :

Но это ведь не значит, что переменные типа int могут хранить дробные значения?

Источник

Урок №31. Целочисленные типы данных: short, int и long

Обновл. 11 Сен 2021 |

На этом уроке мы рассмотрим целочисленные типы данных в языке С++, их диапазоны значений, операцию деления, а также переполнение (что это такое и примеры).

Целочисленные типы данных

Тип Минимальный размер
Символьный тип данныхchar1 байт
Целочисленный тип данныхshort2 байта
int2 байта (но чаще всего 4 байта)
long4 байта
long long8 байт

Примечание: Тип char — это особый случай: он является как целочисленным, так и символьным типом данных. Об этом детально мы поговорим на одном из следующих уроков.

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

Объявление целочисленных переменных

Объявление происходит следующим образом:

Диапазоны значений и знак целочисленных типов данных

Как вы уже знаете из предыдущего урока, переменная с n-ным количеством бит может хранить 2 n возможных значений. Но что это за значения? Это значения, которые находятся в диапазоне. Диапазон — это значения от и до, которые может хранить определенный тип данных. Диапазон целочисленной переменной определяется двумя факторами: её размером (измеряется в битах) и её знаком (который может быть signed или unsigned).

Целочисленный тип signed (со знаком) означает, что переменная может содержать как положительные, так и отрицательные числа. Чтобы объявить переменную как signed, используйте ключевое слово signed :

По умолчанию, ключевое слово signed пишется перед типом данных.

В некоторых случаях мы можем заранее знать, что отрицательные числа в программе использоваться не будут. Это очень часто встречается при использовании переменных для хранения количества или размера чего-либо (например, ваш рост или вес не может быть отрицательным).

Целочисленный тип unsigned (без знака) может содержать только положительные числа. Чтобы объявить переменную как unsigned, используйте ключевое слово unsigned :

1-байтовая целочисленная переменная без знака (unsigned) имеет диапазон значений от 0 до 255.

Обратите внимание, объявление переменной как unsigned означает, что она не сможет содержать отрицательные числа (только положительные).

Теперь, когда вы поняли разницу между signed и unsigned, давайте рассмотрим диапазоны значений разных типов данных:

Для нематематиков: Используем таблицу 🙂

Начинающие программисты иногда путаются между signed и unsigned переменными. Но есть простой способ запомнить их различия. Чем отличается отрицательное число от положительного? Правильно! Минусом спереди. Если минуса нет, значит число — положительное. Следовательно, целочисленный тип со знаком (signed) означает, что минус может присутствовать, т.е. числа могут быть как положительными, так и отрицательными. Целочисленный тип без знака (unsigned) означает, что минус спереди отсутствует, т.е. числа могут быть только положительными.

Что используется по умолчанию: signed или unsigned?

Так что же произойдет, если мы объявим переменную без указания signed или unsigned?

Тип По умолчанию
Символьный тип данныхcharsigned или unsigned (в большинстве случаев signed)
Целочисленный тип данныхshortsigned
intsigned
longsigned
long longsigned

Все целочисленные типы данных, кроме char, являются signed по умолчанию. Тип char может быть как signed, так и unsigned (но, обычно, signed).

В большинстве случаев ключевое слово signed не пишется (оно и так используется по умолчанию).

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

Правило: Используйте целочисленные типы signed, вместо unsigned.

Переполнение

Вопрос: «Что произойдет, если мы попытаемся использовать значение, которое находится вне диапазона значений определенного типа данных?». Ответ: «Переполнение».

Переполнение (англ. «overflow») случается при потере бит из-за того, что переменной не было выделено достаточно памяти для их хранения.

На уроке №28 мы говорили о том, что данные хранятся в бинарном (двоичном) формате и каждый бит может иметь только 2 возможных значения ( 0 или 1 ). Вот как выглядит диапазон чисел от 0 до 15 в десятичной и двоичной системах:

Десятичная система Двоичная система
00
11
210
311
4100
5101
6110
7111
81000
91001
101010
111011
121100
131101
141110
151111

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

Примеры переполнения

Рассмотрим переменную unsigned, которая состоит из 4 бит. Любое из двоичных чисел, перечисленных в таблице выше, поместится внутри этой переменной.

«Но что произойдет, если мы попытаемся присвоить значение, которое занимает больше 4 бит?». Правильно! Переполнение. Наша переменная будет хранить только 4 наименее значимых (те, что справа) бита, все остальные — потеряются.

Например, если мы попытаемся поместить число 21 в нашу 4-битную переменную:

Десятичная система Двоичная система
2110101

Число 21 занимает 5 бит (10101). 4 бита справа (0101) поместятся в переменную, а крайний левый бит (1) просто потеряется. Т.е. наша переменная будет содержать 0101, что равно 101 (нуль спереди не считается), а это уже число 5, а не 21.

Теперь рассмотрим пример в коде (тип short занимает 16 бит):

Результат выполнения программы:

x was: 65535
x is now: 0

Что случилось? Произошло переполнение, так как мы попытались присвоить переменной x значение больше, чем она способна в себе хранить.

Для тех, кто хочет знать больше: Число 65 535 в двоичной системе счисления представлено как 1111 1111 1111 1111. 65 535 — это наибольшее число, которое может хранить 2-байтовая (16 бит) целочисленная переменная без знака, так как это число использует все 16 бит. Когда мы добавляем 1, то получаем число 65 536. Число 65 536 представлено в двоичной системе как 1 0000 0000 0000 0000, и занимает 17 бит! Следовательно, самый главный бит (которым является 1) теряется, а все 16 бит справа — остаются. Комбинация 0000 0000 0000 0000 соответствует десятичному 0, что и является нашим результатом.

Аналогичным образом, мы получим переполнение, использовав число меньше минимального из диапазона допустимых значений:

Результат выполнения программы:

x was: 0
x is now: 65535

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

Правило: Никогда не допускайте возникновения переполнения в ваших программах!

Деление целочисленных переменных

В языке C++ при делении двух целых чисел, где результатом является другое целое число, всё довольно предсказуемо:

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

В языке C++ при делении целых чисел результатом всегда будет другое целое число. А такие числа не могут иметь дробь (она просто отбрасывается, не округляется!).

Правило: Будьте осторожны при делении целых чисел, так как любая дробная часть всегда отбрасывается.

Поделиться в социальных сетях:

Урок №30. Размер типов данных

Комментариев: 23

Всем доброго времени суток. Появился такой вопрос: для объявления без знакового числа, для плюсов, обязательно писать unsigned int X, есть ли сокращенная форма по типу uint X?

Может проще для запоминания было сказать, что тип signed (со знаком) использует 1 (старший бит в байте для записи этого самого знака и для самого числа остается 7 бит (это в случае 1-го байта, для 2- байт 15 и т.д.) и в 7 битах можно записать число не больше чем 128.
К примеру 10000000 это отрицательный ноль. 🙂 Но такого не бывает.

Для того, чтоб числа имели дробь при делении целых чисел можно приписать ноль после точкой. Например : 8.0/5.0 = 1.6

Только это уже совсем другая история)

Достаточно поставить точку одному из выражений. Например: 8. / 5 или 8 / 5.

Остальное компилятор сам подставит)

Вообще, с «железным» правилом «Никогда не допускайте возникновения переполнения в ваших программах!» — сильно погорячились. Потому что очень часто переполнение как раз помогает создать более простой и быстрый код.

Например, нужно много раз увеличивать переменную на 1 и циклически прокручивать все значения от 0 до 255. Писать условие «если равно 255, то присвоить 0» — совсем не нужно, это произойдёт само при прибавлении 1 к 255, если используется 1-байтовая беззнаковая.

Другой очень частый пример: вычисление разности двух значений миллисекундного таймера, чтобы замерить период времени. 4-байтовая переменная с таким таймером переполняется каждые 49 суток. Если система работает непрерывно, то такое может случаться. Когда считаем разность (новое значение таймера минус старое) — возможен случай, когда новое значение уже переполнилось (снова пошло с нуля), а старое ещё нет (огромное число). Но когда вычисляется разность, тут снова произойдёт переполнение (из-за того, что получилось отрицательное значение), и эти два переполнения оказывают взаимно компенсирующее действие, как будто их не было вообще. И разность всё равно будет верной. И не надо городить никаких хитрых алгоритмов.

Скорее всего это какой-то очень древний подход. Никогда не слышал подобного в универе.

Потому что это относится к числам с плавающей точкой. У них отдельный бит хранит знак. В целочисленных типах такого нигде (или почти нигде) нет.

unsigned используется для экономии памяти, это же очевидно. Если знак действительно не нужен за счет дополнительно освобожденного бита, можно увеличить диапазон значений в 2 раза, что в некоторых случаях позволит использовать более «экономные» типы данных.

Ну так нужно указывать другой тип переменной(не целое число). Тогда будет дробь.

Забавная история, почему этот урок так важен =)
В игре Civilization есть баг с механикой агрессии и миролюбия. Суть такова, что агрессивность цивилизации измерялась по шкале от 1 до 10. Девятки и десятки были у всяких Чингисханов, Монтесум и Сталиных, а у духовного пацифиста Махатмы Ганди была единичка. И ещё были модификаторы — строй «республика» уменьшает агрессивность на 1, «демократия» — на 2. Соответственно, сразу же, как только индусы открывали Демократию, у Ганди становилась агрессивность −1.

А теперь внимание. Эта переменная была однобайтная и строго неотрицательная(unsigned), от 0 до 255. Соответственно, агрессивность Махатмы Ганди становилась равна 255 из 10. Поэтому, построив у себя демократию, Ганди двигался рассудком, клепал ядрёные бомбы и умножал всех на ноль.

Действительно хороший пример 🙂 С unsigned нужно быть аккуратным.

Источник

Встроенные типы (C++)

Встроенные типы (также называемые фундаментальными типами) задаются стандартом языка C++ и встроены в компилятор. Встроенные типы не определены в файле заголовка. Встроенные типы делятся на три основные категории: целые, с плавающей запятойи void. Целочисленные типы представляют целые числа. Типы с плавающей запятой могут указывать значения, которые могут содержать дробные части. Большинство встроенных типов рассматриваются компилятором как отдельные типы. Однако некоторые типы являются синонимамиили обрабатываются компилятором как эквивалентные типы.

Тип void

в операторе выражения (Дополнительные сведения см. в разделе выражения.)

в левом операнде оператора запятой (Дополнительные сведения см. в разделе оператор-запятая.)

std:: nullptr_t

Тип Boolean

Символьные типы

Зависящие от Майкрософт: переменные типа помещаются в int тип по signed char умолчанию, если не /J используется параметр компиляции. В этом случае они рассматриваются как тип unsigned char и переносятся в int без расширения знака.

Переменная типа wchar_t является расширенным символом или типом многобайтового символа. Используйте L префикс перед символьным или строковым литералом, чтобы указать тип расширенных символов.

char16_t Тип используется для символьного представления UTF-16. Он должен быть достаточно большим, чтобы представлять любой блок кода UTF-16. Компилятор обрабатывает его как отдельный тип.

char32_t Тип используется для символьного представления UTF-32. Он должен быть достаточно большим, чтобы представлять любую единицу кода UTF-32. Компилятор обрабатывает его как отдельный тип.

Типы с плавающей запятой

Типы с плавающей запятой используют представление IEEE-754, чтобы обеспечить приближение дробных значений к широкому диапазону величин. В следующей таблице перечислены типы с плавающей запятой в C++ и сравнительные ограничения размеров типов с плавающей запятой. Эти ограничения задаются стандартом C++ и не зависят от реализации Майкрософт. Абсолютный размер встроенных типов с плавающей запятой не указан в стандарте.

Конкретно для Майкрософт: представление и double идентично. Однако long double double компилятор обрабатывает как отдельные типы. Компилятор Microsoft C++ использует 4-и 8-байтовые представления с плавающей запятой в формате IEEE-754. Дополнительные сведения см. в разделе IEEE с плавающей точкой.

Целочисленные типы

int Тип является базовым целочисленным типом по умолчанию. Он может представлять все целые числа в диапазоне, зависящем от реализации.

Представление целого числа со знаком — это одно из значений, которое может содержать положительные и отрицательные значения. Он используется по умолчанию или при signed наличии ключевого слова модификатор. unsigned Ключевое слово модификатор задает unsigned представление, которое может содержать только неотрицательные значения.

Реализация должна поддерживать как минимальные требования к размеру, так и отношение размера для каждого типа. Однако фактические размеры могут и зависеть от реализации. См. раздел размеры встроенных типов для деталей реализации, связанных с Майкрософт.

int Ключевое слово можно опустить, если signed unsigned заданы модификаторы, или. Модификаторы и int тип, если они есть, могут использоваться в любом порядке. Например, short unsigned и unsigned int short следует ссылаться на один и тот же тип.

Синонимы целочисленного типа

Компилятор считает синонимами следующие группы типов:

Размеры встроенных типов

Большинство встроенных типов имеют размеры, определенные реализацией. В следующей таблице перечислены объемы хранилища, необходимые для встроенных типов в Microsoft C++. В частности, long имеет 4 байта даже в 64-разрядных операционных системах.

Дополнительные сведения о преобразовании типов см. в разделе стандартные преобразования.

Источник

Data Type Ranges

The Microsoft C++ 32-bit and 64-bit compilers recognize the types in the table later in this article.

int ( unsigned int )

__int8 ( unsigned __int8 )

__int16 ( unsigned __int16 )

__int32 ( unsigned __int32 )

__int64 ( unsigned __int64 )

short ( unsigned short )

long ( unsigned long )

long long ( unsigned long long )

If its name begins with two underscores ( __ ), a data type is non-standard.

The ranges that are specified in the following table are inclusive-inclusive.

Depending on how it’s used, a variable of __wchar_t designates either a wide-character type or multibyte-character type. Use the L prefix before a character or string constant to designate the wide-character-type constant.

The int and unsigned int types have a size of four bytes. However, portable code should not depend on the size of int because the language standard allows this to be implementation-specific.

C/C++ in Visual Studio also supports sized integer types. For more information, see __int8, __int16, __int32, __int64 and Integer Limits.

For more information about the restrictions of the sizes of each type, see Built-in types.

The range of enumerated types varies depending on the language context and specified compiler flags. For more information, see C Enumeration Declarations and Enumerations.

Источник

AVR GCC :: ПЕРЕМЕННЫЕ И КОНСТАНТЫ

Для хранения различных данных в языках программирования используют переменные. Переменной называется область памяти, имеющая имя, которое иначе называют идентификатором.

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

Хорошим стилем является осмысленное именование переменных. Разрешается использовать строчные и прописные буквы, цифры и символ подчёркивания, который в Си считается буквой. Первым символом обязательно должна быть буква, в имени переменной не должно быть пробелов. В современных версиях компиляторов длина имени практически не ограничена. Имя переменной не может совпадать с зарезервированными ключевыми словами. Заглавные и строчные буквы в именах переменных различаются, переменные a и A — разные переменные.

В языке Си все переменные должны быть объявлены. Это означает, что, во-первых, в начале каждой программы или функции Вы должны привести список всех используемых переменных, а во-вторых, указать тип каждой из них.

При объявлении переменной компилятор отводит ей место в памяти в зависимости от её типа. Стандартными средствами AVR GCC работает с типами данных char (символьный тип) и int (целочисленный тип).

Ключевые слова (модификаторы) signed и unsigned указывают, как интерпретируется нулевой бит объявляемой переменной, т.е., если указано ключевое слово unsigned, то нулевой бит интерпретируется как часть числа, в противном случае нулевой бит интерпретируется как знаковый.

Целочисленная величина int может быть short (короткой) или long (длинной).

Объявление переменных

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

Объявление переменной имеет следующий формат:

Инициализация значения переменной при объявлении

При объявлении переменную можно проинициализировать, то есть присвоить ей начальное значение. Сделать это можно следующим образом. Таким образом, в переменную x при объявлении сразу же будет записано число 100.

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

Для присваивания в Си служит знак «=». Выражение, стоящее справа от знака присваивания, вычисляется, и полученное значение присваивается переменной, стоящей слева от знака присваивания. При этом предыдущее значение, хранящееся в переменной, стирается и заменяется на новое.

Оператор «=» не следует понимать как равенство.
Например, выражение a = 5; следует читать как «присвоить переменной a значение 5».

Примеры:
В правой части значение переменной может использоваться несколько раз:

Арифметические операции

Арифметические операции записываются в выражениях следующим образом:

+плюс
минус
*умножить
/разделить

Пример:
Таким образом, в переменной z будет храниться число 23

Дополнительные способы присваивания

Кроме простого оператора присваивания «=», в Си существует еще несколько комбинированных операторов присваивания: «+=», «-=», «*= Инкремент и декремент

Пример:
Инкремент и декремент относятся к операциям присваивания. При использовании декремента и инкремента совместно с оператором присваивания «=» применяют постфиксную (x++) или префиксную (++x) запись. Первой выполняется префиксная запись.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *