Простые типы данных в c: C++ | Типы данных

Содержание

Типы данных в C#

Вы здесь: Главная - C# - Основы C# - Типы данных в C#

C# - это статически типизированный язык программирования. Поэтому перед тем как использовать переменную в C# Вы должны определить ее тип. Тип переменной задает ограничение на значение переменной, а также виды операций, которые можно выполнять с ней.

Итак, таблица с типами переменных в C# представлена ниже:

Тип данных Размер Описание
int 4 байта Хранит целые числа в диапазоне от -2,147,483,648 до 2,147,483,647
long 8 байт Хранит целые числа в диапазоне от -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807
float 4 байта Хранит дробные числа с точностью до 7 знаков после запятой
double 8 байт Хранит дробные числа с точностью до 15 знаков после запятой
bool 1 бит Хранит логические значения true или false
char 2 байта Хранит один символ/букву в одинанрных кавычках
string 2 байта на символ Хранит последовательность символов, обрамленных в двойные кавычки

Числа

Числа в C# делятся на две большие группы:

  • Целочисленные типы - к ним относятся int и double
  • Числа с плавающей запятой - float и double

Как правило в C# наиболее часто используются тип int и double.

int number1 = 100            // целое число
long number2 = 230000000000L // целое число типа long

float number3 = 10.12F
double number4 = 1999399.23737D

Как говорилось ранее,

типы float и double отличаются друг от друга диапазоном значений и количеством знаков после запятой. Так какой же из типов использовать?

Точность значения с плавающей запятой (float) указывает, сколько цифр это значение может иметь после десятичной точки. Точность float составляет всего шесть или семь десятичных цифр, в то время как double переменные имеют точность около 15 цифр. Поэтому для большинства расчетов безопаснее использовать double.

Логические переменные

Логический тип данных в C# объявляется с ключевым словом bool и может принимать только значения true или false. Логические значения в основном используются в условных выражениях:

bool isTrue  = true;
bool isFalse = false;

Символы и строки

char symbol = 'C' // один символ в одинарных кавычках!

string str = "как так строка"

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

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

  • Создано 01.12.2020 12:27:42
  • Михаил Русаков
Предыдущая статья Следующая статья

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:
    <a href="https://myrusakov. ru" target="_blank"><img src="https://myrusakov.ru/images/button.gif" alt="Как создать свой сайт" /></a>

    Она выглядит вот так:

  2. Текстовая ссылка:
    <a href="https://myrusakov.ru" target="_blank">Как создать свой сайт</a>

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):
    [URL="https://myrusakov.ru"]Как создать свой сайт[/URL]

Типы данных, определяемые пользователем в C++

В реальных задачах информация, которую требуется обрабатывать, может иметь достаточно сложную структуру. Для ее адекватного представления используются типы данных, построенные на основе простых типов данных, массивов и указателей. Язык C++ позволяет программисту определять свои типы данных и правила работы с ними. Исторически для таких типов сложилось наименование, вынесенные в название статьи, хотя правильнее было бы назвать их типами, определяемыми программистом.

Переименование типов (typedef)

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

typedef тип новое_имя [ размерность ];

В данном случае квадратные скобки являются элементом синтаксиса. Размерность может отсутствовать. Примеры:

typedef unsigned int UINT;
typedef char Msg[100];
typedef struct{
char f1o[30];
int date, code;
double salary;} Worker;

Введенное таким образом имя можно использовать таким же образом, как и имена стандартных типов:

UINT i, j ; // две переменных типа unsigned int
Msg str[10]; // массив из 10 строк по 100 символов
Worker staff[100]; // массив из 100 структур

Кроме задания типам с длинными описаниями более коротких псевдопимов, typedef используется для облегчения переносимости программ: если машинно-зависимые типы объявить с помощью операторов typedef, при переносе программы потребуется внести изменения только в эти операторы.

Перечисления (enum)

При написании программ часто возникает потребность определить несколько именованных констант, для которых требуется, чтобы все они имели различные значения (при этом конкретные значения могут быть не важны). Для этого удобно воспользоваться перечисляемым типом данных, все возможные значения которого задаются списком целочисленных констант. Формат:

enum [ имя_типа ] { список_констант };

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

enum Err {ERR__READ, ERR__WRITE, ERR_CONVERT};
Err error;
switch (error){
case ERR_READ: /* операторы */ break;
case ERR_WRITE: /* операторы */ break;
case ERR_CONVERT: /* операторы */ break;
}

Константам ERR_READ, ERR_WRITE, ERR_CONVERT присваиваются значения 0, 1 и 2 соответственно.

Другой пример:

enum {two = 2, three, four, ten = 10, eleven, fifty = ten + 40};

Константам three и four присваиваются значения 3 и 4, константе eleven — 11.

Имена перечисляемых констант должны быть уникальными, а значения могут совпадать. Преимущество применения перечисления перед описанием именованных констант и директивой #define состоит в том, что связанные константы нагляднее; кроме того, компилятор при инициализации констант может выполнять проверку типов.

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

Примечание

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

Структуры (struct)

В отличие от массива, все элементы которого однотипны, структура может содержать элементы разных типов. В языке C++ структура является видом класса и обладает всеми его свойствами, но во многих случаях достаточно использовать структуры так, как они определены в языке С:

struct [ имя_типа ] {
тип_1 элемент_1:
тип_2 элемент_2;
тип_n элемент_n;
} [ список_описателей ];

Элементы структуры называются полями структуры и могут иметь любой тип, кроме типа этой же структуры, но могут быть указателями на него. Если отсутствует имя типа, должен быть указан список описателей переменных, указателей или массивов. В этом случае описание структуры служит определением элементов этого списка:

// Определение массива структур и указателя на структуру:
struct {
char f1o[30];
int date, code;
double salary;
}staff[100], *ps;

Если список отсутствует, описание структуры определяет новый тип, имя которого можно использовать в дальнейшем наряду со стандартными типами, например:

struct Worker{ // описание нового типа Worker
char f1o[30];
int date, code;
double salary;
}; // описание заканчивается точкой с запятой
// определение массива типа Worker и указателя на тип Worker:
Worker staff[100], *ps;[/ccie_cpp]

Имя структуры можно использовать сразу после его объявления (определение можно дать позднее) в тех случаях, когда компилятору не требуется знать размер структуры, например:

struct List;. // объявление структуры List
struct Link{
List *p; // указатель на структуру List
Link *prev, *succ; // указатели на структуру Link
};
struct List { / * определение структуры List * / };

Это позволяет создавать связные списки структур.

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

struct{
char fio[30];
int date, code;
double salary;
}worker = {"Страусенке". 31. 215. 3400.55};

При инициализации массивов структур следует заключать в фигурные скобки каждый элемент массива (учитывая, что многомерный массив — это массив массивов):

struct complex{
float real, im;
} compl [2][3] = {
{{1. 1}. {1. 1}. {1. 1}}. // строка 1. TO есть массив compl[0]
{{2. 2}. {2. 2}. {2. 2}} // строка 2. то есть массив compl[1]
};

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

Доступ к полям структуры выполняется с помощью операций выбора . (точка) при обращении к полю через имя структуры и -> при обращении через указатель, например:

Worker worker, staff[100], *ps;
worker.fio = "Страусенке";
staff[8].code = 215;
ps->salary = 0.12;

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

struct А {int а; double х;};
struct В {А а; double х;} х[2];
х[0].а.а = 1;
х[1].х = 0.1;

Как видно из примера, поля разных структур могут иметь одинаковые имена, поскольку у них разная область видимости. Более того, можно объявлять в одной области видимости структуру и другой объект (например, переменную или массив) с одинаковыми именами, если при определении структурной переменной использовать слово struct, но не советую это делать — запутать компилятор труднее, чем себя.

Битовые поля

Битовые поля — это особый вид полей структуры. Они используются для плотной упаковки данных, например, флажков типа «да/нет». Минимальная адресуемая ячейка памяти — 1 байт, а для хранения флажка достаточно одного бита. При описании битового поля после имени через двоеточие указывается длина поля в битах (целая положительная константа):

struct Options{
bool centerX:1;
bool centerY:1;
unsigned int shadow:2;
unsigned int palette:4;
};

Битовые поля могут быть любого целого типа. Имя поля может отсутствовать, такие поля служат для выравнивания на аппаратную границу. Доступ к полю осуществляется обычным способом — по имени. Адрес поля получить нельзя, однако в остальном битовые поля можно использовать точно так же, как обычные поля структуры. Следует учитывать, что операции с отдельными битами реализуются гораздо менее эффективно, чем с байтами и словами, так как компилятор должен генерировать специальные коды, и экономия памяти под переменные оборачивается увеличением объема кода программы. Размещение битовых полей в памяти зависит от компилятора и аппаратуры.

Объединения (union)

Объединение (union) представляет собой частный случай структуры, все поля которой располагаются по одному и тому же адресу. Формат описания такой же, как у структуры, только вместо ключевого слова struct используется слово union. Длина объединения равна наибольшей из длин его полей, В каждый момент времени в переменной типа объединение хранится только одно значение, и ответственность за его правильное использование лежит на программисте.

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

#include
int niain(){
  enum paytype {CARD, CHECK};
  paytype ptype;
  union payment{
    char card[25];
    long check;
  } info;
   /* присваивание значений info и ptype */
  switch (ptype){
    case CARD: cout << "Оплата no карте: " << info. card; break;
    case CHECK: cout << "Оплата чеком: " << info.check; break;
  }
  return 0;
}

Объединение часто используют в качестве поля структуры, при этом в структуру удобно включить дополнительное поле, определяющее, какой именно элемент объединения используется в каждый момент. Имя объединения можно не указывать, что позволяет обращаться к его полям непосредственно:

#include
int niain(){
  enum paytype {CARD, CHECK};
  struct{
  paytype ptype;
    union payment{
      char card[25];
      long check;
    }
  } info;
   /* присваивание значений info и ptype */
  switch (ptype){
    case CARD: cout << "Оплата no карте: " << info.card; break;
    case CHECK: cout << "Оплата чеком: " << info.check; break;
  }
  return 0;
}

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

struct Options{
bool centerX:1;
bool centerY:1;
unsigned int shadow:2;
unsigned int palette:4;
}
union{
unsigned char ch;
Options bit;
}option = {0xC4};
cout << option.bit.palette;
option.ch &= 0xF0; // наложение маски

По сравнению со структурами на объединения налагаются некоторые ограничения. Смысл некоторых из них станет понятен позже:

  • объединение может инициализироваться только значением его первого элемента;
  • объединение не может содержать битовые поля;
  • объединение не может содержать виртуальные методы, конструкторы, деструкторы и операцию присваивания;
  • объединение не может входить в иерархию классов.

По материалам книги Т.А. Павловской «C\C++. Программирование на языке высокого уровня».

Типы данных

Все типы данных в языка C# являются производными базового класса Object, и, таким образом, наследуют все его члены. Описание класса Object содержится в пространстве имен System. Класс Object обладает статическими методами:
  • Equals(Object, Object) проверяет равенство двух указанных экземпляров объектов, возвращает логическое значение.
  • ReferenceEquals(Object, Object) проверяет, являются ли переданные объекты одним и тем же объектом, возвращает логическое значение.

К нестатическим методам класса Object относятся
  • Equals(Object) – вызывается для конкретного экземпляра и проверяет равенство этого экземпляра объекту, переданному в качестве аргумента, возвращает логическое значение.
  • Finalize() – пытается освободить ресурсы памяти, занимаемые объектом.
  • GetHashCode() – генерирует хэш-код для объекта.
  • GetType() – возвращает тип текущего объекта.
  • MemberwiseClone() – создает еще один объект того же типа и копирует в него все данные нестатических полей текущего объекта.
  • ToString() – преобразует объект к строковому представлению.

Все типы данных C#, унаследованные от класса Object, можно разделить на:
  • Простые данные – для использования данных таких типов достаточно указать только имя переменной или величину константы. К ним относятся логические значения, целые и вещественные числа, а также символьные значения.
  • Агрегирующие данные – данные, содержащие внутри себя несколько значений полей. К ним относятся массивы, перечисления, структуры, классы.

Другое деление типов данных на
  • Базовые, или встроенные – это типы данных, которые содержатся в стандарте языка. К ним относятся простые базовые типы, а также строковый тип string.
  • Библиотечные – это типы, которые содержатся в библиотеках, обычно .NET Framework. Чтобы использовать библиотечные типы данных необходимо знать их поля и методы, а также пространство имен, в котором они описаны.
  • Пользовательские – определенные программистом.

В таблице перечислены встроенные типы языка C#, их размер и диапазон представления.
Тип данныхПсевдоним
.NET Framework
Размер, байтДиапазон
byte System.Byte 1 -128...127
sbyte System.SByte 1 0...255
short System.Int16 2 -32768...32767
ushort System.UInt16 2 0...65535
int System.Int32 4 2 147 483 648 ... 2 147 483 647
uint System.UInt32 4 0 ... 4 294 967 295
long System.Int64 8 -9 223 372 036 854 775 808 ...
9 223 372 036 854 775 807
ulong System.UInt64 8 0 . .. 18 446 744 073 709 551 615
bool System.Boolean 1 True, False
float System.Single 4 ±1,5×10−45 ... ±3,4 × 1038
double System.Double 8 ±1,5×10−45 ... ±3,4 × 1038
decimal System.Decimal 16 ±1,0×10−28 ... ±7,9 × 1028
char System.Char 2 Символ Юникода
string System.String Строка символов Юникода
Все перечисленные типы, за исключением string, являются простыми.
Поскольку C# является языком со строгой типизацией данных, любая переменная перед ее использованием должна быть объявлена. Причем область видимости переменной ограничивается пространством имен, в котором она объявлена.
Для объявления переменных используется следующий синтаксис. Без инициализации
С инициализацией
Если необходимо объявить несколько переменных одного типа, то они могут быть записаны после названия типа через запятую.
Если переменная объявлена без инициализации, ей присваивается значение по умолчанию, равное 0.

Целочисленные данные


Встроенные типы данных языка C# включают 1-байтное, 2-байтное, 4-байтное и 8-байтное представление целочисленных данных в знаковой и беззнаковой форме.
Для знаковой формы представления старший разряд числа отводится под хранение его знака, поэтому диапазон представления значащей части чисел со знаком в 2 раза меньше, чем для беззнаковых.
Для инициализации целочисленных данных чаще всего используются целочисленные константы, записанные с помощью цифр десятичной или шестнадцатеричной системы счисления. Шестнадцатеричная константа начинается с символов 0x или 0X. Для отрицательных констант используется предшествующий символ ю
Пример объявления целочисленных переменных:
Все целочисленные данные имеют константные поля MaxValue и MinValue, содержание максимальное и минимальное значения, которые могут быть представлены данными соответствующего типа.

Логические данные


Логические данные представлены логическим типом bool. Несмотря на то, что данные логического типа могут принимать только одно из двух значений True или False, объем памяти, отводимый для хранения логических переменных составляет 1 байт.

Вещественные данные


Представление вещественных данных представляет собой диапазон, симметричный относительно нуля. При выполнении операций с плавающей точкой не создаются исключения, а в исключительных ситуациях возвращается 0 (в случае слишком маленького значения), бесконечность PositiveInfinity (в случае большого положительного значения) или NegativeInfinity (в случае большого по величине отрицательного значения) или нечисловое значение (NaN) если операция с плавающей точкой является недопустимой.
Для инициализации вещественных чисел могут использоваться константы. Вещественное число состоит из знака, целой части, дробной части и порядка числа. В качестве разделителя целой и дробной части в тексте программы используется точка. Порядок числа представляет собой степень 10, на которую следует умножить значащую часть вещественного числа.
Примеры объявления вещественных констант Представление вещественного числа со знаком включает в себя целую часть, дробную часть и порядок числа.
По умолчанию все вещественные константы имеют тип double. Если последним символом константы указан суффикс f или F, константа имеет тип float. Если последним символом константы указан суффикс m или M, константа имеет тип decimal.
В силу особенностей представления вещественных чисел в разрядной сетке вычислительной машины, при работе с вещественными числами могут возникнуть проблемы, связанные с точностью их представления. Наименьшее целое вещественное число, которое может быть представлено в разрядной сетке float или double определяется константным полем Epsilon этих типов.
Тип decimal обладает более точным и узким диапазоном по сравнению с типами float и double, и поэтому больше подходит для использования в финансовых расчетах.

Символьные данные


Символьная переменная представляет собой 2-байтное значение типа char, являющееся символом таблицы Юникод. Для инициализации символьных данных могут использоваться константы следующих типов Все символьные представления констант заключаются в апострофы ''.

Строковые данные


Несмотря на то, что строковый тип данных не является простым, он является встроенным типом языка C#. Строковый тип данных string позволяет создавать строки любой длины, для инициализации которых используется последовательность символов, заключенная в кавычки "...". Тип данных string также содержит ряд методов для обработки строковых данных.

Закрепить использование базовых типов данных Вы можете в разделе Типы данных курса Алгоритмика

Автор: Вставская Елена Владимировна

 
Написать комментарий:

C++ - Типы данных

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

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

Примитивные встроенные типы

C ++ предлагает программисту богатый набор встроенных, а также пользовательских типов данных. В следующих таблицах перечислены семь основных типов данных C ++:

Type Keyword
Boolean bool
Character char
Integer int
Floating point float
Double floating point double
Valueless void
Wide character wchar_t

Некоторые из основных типов могут быть изменены с использованием одного или нескольких модификаторов этого типа:

  • signed
  • unsigned
  • short
  • long

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

Type Typical Bit Width Typical Range
char 1byte -127 to 127 or 0 to 255
unsigned char 1byte 0 to 255
signed char 1byte -127 to 127
int 4bytes -2147483648 to 2147483647
unsigned int 4bytes 0 to 4294967295
signed int 4bytes -2147483648 to 2147483647
short int 2bytes -32768 to 32767
unsigned short int Range 0 to 65,535
signed short int Range -32768 to 32767
long int 4bytes -2,147,483,648 to 2,147,483,647
signed long int 4bytes same as long int
unsigned long int 4bytes 0 to 4,294,967,295
float 4bytes +/- 3. 4e +/- 38 (~7 digits)
double 8bytes +/- 1.7e +/- 308 (~15 digits)
long double 8bytes +/- 1.7e +/- 308 (~15 digits)
wchar_t 2 or 4 bytes 1 wide character

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


#include <iostream>
using namespace std;

int main() {
   cout << "Size of char : " << sizeof(char) << endl;
   cout << "Size of int : " << sizeof(int) << endl;
   cout << "Size of short int : " << sizeof(short int) << endl;
   cout << "Size of long int : " << sizeof(long int) << endl;
   cout << "Size of float : " << sizeof(float) << endl;
   cout << "Size of double : " << sizeof(double) << endl;
   cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;
   
   return 0;
}

В этом примере используется endl , который вводит символ новой строки после каждой строки, а оператор << используется для передачи нескольких значений на экран.  Мы также используем оператор sizeof () для получения размера различных типов данных.

Когда приведенный выше код компилируется и выполняется, он производит следующий результат, который может варьироваться от машины к машине:


Size of char : 1
Size of int : 4
Size of short int : 2
Size of long int : 4
Size of float : 4
Size of double : 8
Size of wchar_t : 4

Декларации typedef

Вы можете создать новое имя для существующего типа с помощью typedef. Ниже приведен простой синтаксис для определения нового типа с использованием typedef:


typedef type newname; 

Например, следующее говорит компилятору, что ногами является другое имя для int:


typedef int feet;

Теперь следующая декларация совершенно легальна и создает целочисленную переменную, называемую расстоянием:


feet distance;

Перечисленные типы

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


enum enum-name { list of names } var-list; 

Здесь enum-name - это имя типа перечисления. Список имен разделяется запятой. Например, следующий код определяет перечисление цветов, называемых цветами, и переменной c цвета типа. Наконец, c присваивается значение «blue».


enum color { red, green, blue } c;
c = blue;

По умолчанию значение первого имени равно 0, второе имя имеет значение 1, а третье - значение 2 и т. Д. Но вы можете указать имя, определенное значение, добавив инициализатор. Например, в следующем перечислении зеленый будет иметь значение 5.


enum color { red, green = 5, blue };

Здесь blue будет иметь значение 6, потому что каждое имя будет больше, чем предыдущее.

C Урок 4. Переменные и типы данных. Часть 1 |

&nbsp

&nbsp

&nbsp

Продолжаем освоение языка C.

И теперь пришло время познакомиться с типами данных, а также способами их представления, одним из которых являются переменные. Также есть ещё константы, но с ними мы будем знакомиться немного позже.

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

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

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

Данные различного типа – это величины, которые располагаются в каком-то месте памяти и могут занимать в ней различное количество пространства.

Типы данных можно разделить условно на три группы:

  1. целые – данные целого типа,
  2. вещественные – данные, которые могут иметь дробную часть,
  3. символы – данные типа char, которые представляют собой какой-то символ и занимают в памяти всего один байт.

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

Рассмотрим, какие бывают данные целого типа (в принципе char тоже можно считать целым типом малой величины, так как зачастую его используют в этом качестве, когда хотят оперировать малыми значениями, чтобы сэкономить память, так как они занимают в ней всего один байт).

Данная таблица, думаю, всё это расскажет:

 

Тип Количество бит Допустимый диапазон
char 8 -128 … 127
unsigned char 8 0 … 255
short
16 -32 768 … 32767
unsigned short
16 0 … 65535
int
32 -2 147 483 648 … 2 147 483 647
unsigned int
32 0 … 4 294 967 295
long 32 -2 147 483 648 … 2 147 483 647
unsigned long 32 0 … 4 294 967 295
long long
64

-9 223 372 036 854 775 808 …

9 223 372 036 854 775 807

unsigned long long 64 0 … 18 446 744 073 709 551 615

 

Аналогичным образом ведёт себя и вещественный тип. Только представители данного типа могут иметь ещё некоторые свойства. Кроме того, что они тоже занимают в памяти каждый определенное количество байт и имеют диапазоны, они могут быть представлены ещё в нормированной форме – в виде числа, умноженного на 10 в определённой степени. Также данный вид представления называют экспоненциальной записью числа.

Например, число 135.543 можно представить как 1,35543 . 102.

А, например, число 0.00001245 – как 1.245 . 10-5.

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

В коде мы так написать не можем, в исходном коде первое число будет выглядеть как 1.35543E2, а второе 1. 245E-5.

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

Также посмотрим таблицу диапазонов и размера занимаемой памяти определённых вещественных типов

 

Тип Количество бит Допустимый диапазон
float 32 -2 147 483 648.0 … 2 147 483 647.0
double 64

-9 223 372 036 854 775 808 .0 …

9 223 372 036 854 775 807.0

long double
64

-9 223 372 036 854 775 808 .0 …

9 223 372 036 854 775 807.0

 

В некоторой документации пишут, что последний тип занимает 80 бит в памяти. Пока не знаю, где правда, возможно это зависит от операционных систем, либо от каких-то стандартов, либо от компилятора. С этим, думаю, разберёмся позже, когда будем писать исходные коды, отлаживать их и смотреть результаты в дизассемблированном виде.

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

Ещё существует тип данных bool. Это целочисленный тип данных, так как диапазон допустимых значений — целые числа от 0 до 255. Данный тип используется как логический тип данных исключительно для хранения результатов логических выражений. У логического выражения может быть один из двух результатов – true или false. true — если логическое выражение истинно, false — если логическое выражение ложно. Данный тип может отсутствовать в некоторых компиляторах вообще, тогда мы используем вместо него char либо unsigned char.

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

Теперь о переменных.

Переменные существуют для хранения значений и величин определённых типов данных в памяти.

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

Самое основное требование для объявления переменной: переменная должна быть объявлена раньше, чем она будет использоваться.

 

 

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

 

char symbol1;

 

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

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

Имя переменной для удобства должно отражать суть и назначение нашей переменной, она должна показывать нам, для чего мы её используем, то есть имя должно быть говорящим. Конечно, это не обязательно и никакие стандарты этого не предусматривают и делать это мы должны только для своего удобства, чтобы наш код легче потом читался. Так как язык C – язык для программиста, а ассемблер – это язык для процессора.

Тем не менее существует и стандарт для имени переменной. Не всякие символы можно использовать в имени переменной. можно использовать буквы только латинского алфавита, как верхнего так и нижнего регистра, причём язык C является языком регистрозависимым и, например, переменные с именами Symbol1 и symbol1 – это будут разные переменные.

Также разрешается использовать арабские цифры в именах переменных (от 0 до 9), только с одним ограничением – имя переменной не должно начинаться с цифры, например имя переменной 4symbol использовать запрещено, а s4ymbol – разрешено.

В именах переменных запрещено использовать пробелы, поэтому, например, имя переменной first var запрещено. Но чтобы нам как-то можно было больше рассказать о назначении переменных и всё же использовать там несколько слов, то вместо пробелов разрешено использовать подчёркивания – '_'. Поэтому мы сможем нашу переменную назвать как first_var. Также со знака подчёркивания допустимо начинать имя переменной, но злоупотреблять этим нежелательно, так как во многих библиотеках, в т.ч. стандартных, переменные, имя которых начинается со знака подчёркивания, очень часто используется. Тем самым мы избежим повторения имён, которое недопустимо.

Запрещено также в качестве имён использовать ключевые слова – такие, к примеру, как if, else, int, float. Данные слова зарезервированы и не могут быть использованы.

Также не допускается использование в именах операторов (+, -, = и т.д.), кавычек, скобок и т.д.

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

Несколько переменных мы можем объявить как в разных строках

 

char symbol1;

int cnt;

float adc_val;

 

так и в одной

 

char symbol1; int cnt; float adc_val;

 

Если переменные объявляются одного типа, то мы можем их объединить в одно объявление. В этом случае имена данных переменных между собой мы разделяем запятыми

 

char symbol1, symbol2, symbol3;

 

В случае всех вышеперечисленных операций под переменные, которые мы объявили резервируется место в памяти в таком размере, какой предусматривает тип переменной, которую мы объявляем. В этом случае содержимое резервируемых ячеек памяти как правило не изменяется и значение переменной приобретёт случайную величину. Некоторые компиляторы автоматически присваивают значение 0 объявляемым переменным.

Чтобы переменная приобрела определённое значение, её следует либо инициализировать, либо присвоить ей результат какой-то операции.

Так как с различными операциями мы будем знакомиться не в данном уроке, то познакомимся пока с первым типом придания определённого значения переменной – это её инициализация.

Инициализируются переменные различными способами.

Мы можем сначала наши переменные объявить, а затем инициализировать

 

char symbol1, symbol2, symbol3;

int cnt;

float adc_val;

symbol1 = 'c';

symbol2 = 'f';

symbol3= 'h';

cnt = 589;

adc_val = 124.54f;

 

Таким образом мы присвоили нашим переменным определённые значения. Теперь мы с нашими переменными в дальнейшем можем осуществлять какие-то действия – арифметические, логические, также использовать их в параметрах вызываемых функций, например, с помощью функции printf вывести их значения в консоль.

Также мы можем проделать инициализацию наших переменных сразу – на этапе объявления

 

char symbol1 = 'c', symbol2 = 'f', symbol3= 'h';

int cnt = 589;

float adc_val = 124.54f;

 

Оператор '=' (равно) – это оператор присвоения. Используется для присвоения переменной, имя которой находится слева от оператора, значения либо результата выражения, находящегося справа от оператора.

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

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

 

Предыдущий урок Программирование на C Следующая часть

 

Исходный код

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

Post Views: 6 095

Вся правда о целочисленных типах в C / Хабр

Для начала несколько вопросов:
  1. Тип char по умолчанию знаковый или нет? А int?
  2. Законно ли неявное приведение (signed char *) к (char *)? А то же для int?
  3. Сколько бит в unsigned char?
  4. Какое максимальное число гарантированно можно поместить в int? А минимальное?
  5. Тип long определённо больше, чем char, не так ли?

Разумеется, экспериментально искать ответы на эти вопросы с помощью вашего любимого компилятора в вашей любимой системе на вашем любимом компьютере1) — не лучшая идея. Мы говорим о стандарте языка (С99 и новее).

Если вы уверенно сможете правильно ответить на эти вопросы, тогда эта статья не для вас. В противном случае десять минут, потраченные на её чтение, будут весьма полезны.

Предположу, что вы ответили
  1. Знаковые оба.
  2. Законны оба.
  3. 8.
  4. 2147483647. -2147483648.
  5. Конечно, Кэп.


А правильные ответы такие
  1. char — не регламентируется, int — знаковый.
  2. Для int — законно, а для char — нет.
  3. Не менее 8.
  4. 32767. -32767
  5. Вообще говоря, нет.

Про signed и unsigned

Все целочисленные типы кроме char, по умолчанию знаковые (signed).

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

Хотя формально это три разных типа, но фактически char эквивалентен либо signed char, либо unsigned char — на выбор компилятора (стандарт ничего конкретного не требует).

Подробнее про char я написал в комментариях.

О размере unsigned char

Тип unsigned char является абстракцией машинного байта. Важность этого типа проявляется в том, что С может адресовать память только с точностью до байта. На большинстве архитектур размер байта равен 8 бит, но бывают и исключения. Например, процессоры с 36-битной архитектурой как правило имеют 9-битный байт, а в некоторых DSP от Texas Instruments байты состоят из 16 или 32 бит. Древние архитектуры могут иметь короткие байты из 4, 5 или 7 бит.

Стандарт С вынужден отказаться от допотопных архитектур и требует, чтобы байты были как минимум 8-битные. Конкретное значение (CHAR_BIT2)) для данной платформы записано в заголовочном файле limits.h.

Размеры целочисленных типов в С

C переносимый, поэтому в нём базовые целочисленные типы (char, short, int и др.) не имеют строго установленного размера, а зависят от платформы. Однако эти типы не были бы переносимы, если бы
их размеры были совершенно произвольные: стандарт устанавливает минимальные диапазоны принимаемых значений для всех базовых целочисленные типов. А именно,
  • signed char: -127...127 (не -128...127; аналогично другие типы)
  • unsigned char: 0...255 (= 28−1)
  • signed short: -32767...32767
  • unsigned short: 0...65535 (= 216−1)
  • signed int: -32767...32767
  • unsigned int: 0...65535 (= 216−1)
  • signed long: -2147483647...2147483647
  • unsigned long: 0...4294967295 (= 232−1)
  • signed long long: -9223372036854775807...9223372036854775807
  • unsigned long long: 0...18446744073709551615 (= 264−1)

Стандарт требует, чтобы максимальное значение unsigned char было 2CHAR_BIT−1 (см. предыдущий пункт).

Стандарт требует sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long). Таким образом, вполне законны ситуации типа sizeof(char)=sizeof(long)=32. Для некоторых DSP от Texas Instruments так и есть.

Конкретные значения этих диапазонов для данной платформы указаны заголовочном файле limits.h.

Новые типы в С99

После того, как C99 добавил тип long long, целочисленных типов и путаницы стало ещё больше. Чтобы навести порядок, стандарт ввёл заголовочный файл stdint.h, где определяются типы вроде int16_t (равно 16 бит), int_least16_t (минимальный тип, способный вместить 16 бит), int_fast16_t (по крайней мере 16 бит, работа с этим типом наиболее быстрая на данной платформе) и т. п.

least- и fast-типы фактически являются заменой рассмотренных выше типов int, short, long и т. п. только вдобавок дают программисту возможность выбора между скоростью и размером.

От типов вроде int16_t, со строгим указанием размера, страдает переносимость: скажем, на архитектуре с 9-битным байтом может просто не найтись 16-битного регистра. Поэтому стандарт тут явно говорит, что эти типы опциональны. Но учитывая, что какой бы код вы ни писали, чуть менее чем во всех случаях целевая архитектура фиксирована даже в худшем случае с точностью до семейства (скажем, x86 или AVR), внутри которого, размер байта не может вдруг поменяться, то переносимость фактически сохраняется. Более того, типы вроде int16_t оказались даже более популярными, чем int_least16_t и int_fast16_t, а при низкоуровневом программировании (микроконтроллеры, драйверы устройств) и подавно, ибо там зачастую неопределённость размера переменной просто непозволительна.



1) Для удобства тройку архитектура+ОС+компилятор далее будем называть просто платформой.
2) Этот макрос правильнее было бы назвать UCHAR_BIT, но по причинам совместимости он называется так, как называется.

Типы данных в C #

  • Подписывайтесь на нас