Операции над обобщенными функциями. Обобщённая функция

Теги: Си переменные. char, int, unsigned, long, long long, float, double, long double, long float, lexical scoping. Объявление переменных. Область видимости. Инициализация переменных. Имена переменных. Экспоненциальная форма.

Переменные

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

auto double int struct
break else long switch
register typedef char extern
return void case float
unsigned default for signed
union do if sizeof
volatile continue enum short
while inline
А также ряд других слов, специфичных для данной версии компилятора, например far , near , tiny , huge , asm , asm_ и пр.

Например, правильные идентификаторы
a, _, _1_, Sarkasm, a_long_variable, aLongVariable, var19, defaultX, char_type
неверные
1a, $value, a-long-value, short

Си - регистрозависимый язык. Переменные с именами a и A, или end и END, или perfectDark и PerfectDarK – это различные переменные.

Типы переменных

Т ип переменной определяет

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

Целые

  • char - размер 1 байт. Всегда! Это нужно запомнить.
  • short - размер 2 байта
  • int - размер 4 байта
  • long - размер 4 байта
  • long long - размер 8 байт.
Здесь следует сделать замечание. Размер переменных в си не определён явно, как размер в байтах. В стандарте только указано, что

char <= short <= int <= long <= long long

Указанные выше значения характерны для компилятора VC2012 на 32-разрядной машине. Так что, если ваша программа зависит от размера переменной, не поленитесь узнать её размер.

Теперь давайте определим максимальное и минимальное число, которое может хранить переменная каждого из типов. Числа могут быть как положительными, так и отрицательными. Отрицательные числа используют один бит для хранения знака. Иногда знак необходим (например, храним счёт в банке, температуру, координату и т.д.), а иногда в нём нет необходимости (вес, размер массива, возраст человека и т.д.). Для этого в си используется модификатор типа signed и unsigned. unsigned char - все 8 бит под число, итого имеем набор чисел от 00000000 до 11111111 в двоичном виде, то есть от 0 до 255 signed char от -128 до 128. В си переменные по умолчанию со знаком. Поэтому запись char и signed char эквивалентны.

Таб. 1 Размер целых типов в си.
Тип Размер, байт Минимальное значение Максимальное значение
unsigned char 1 0 255
signed char
(char)
1 -128 127
unsigned short 2 0 65535
signed short
(short)
2 -32768 32767
unsigned int
(unsigned)
4 0 4294967296
signed int
(int)
4 -2147483648 2147483647
unsigned long 4 0 4294967296
signed long
(long)
4 -2147483648 2147483647
unsigned long long 8 0 18446744073709551615
signed long long
(long long)
8 -9223372036854775808 9223372036854775807

sizeof

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

#include #include int main() { char c; short s; int i; long l; long long L; //Вызов sizeof как "функции" printf("sizeof(char) = %d\n", sizeof(c)); printf("sizeof(short) = %d\n", sizeof(s)); printf("sizeof(int) = %d\n", sizeof(i)); printf("sizeof(long) = %d\n", sizeof(l)); printf("sizeof(long long) = %d\n", sizeof(L)); //Вызов как оператора printf("sizeof(char) = %d\n", sizeof c); printf("sizeof(short) = %d\n", sizeof s); printf("sizeof(int) = %d\n", sizeof i); printf("sizeof(long) = %d\n", sizeof l); printf("sizeof(long long) = %d\n", sizeof L); _getch(); }

(Я думаю ясно, что переменные могут иметь любое валидное имя). Эту программу можно было написать и проще

#include #include int main() { printf("sizeof(char) = %d\n", sizeof(char)); printf("sizeof(short) = %d\n", sizeof(short)); printf("sizeof(int) = %d\n", sizeof(int)); printf("sizeof(long) = %d\n", sizeof(long)); printf("sizeof(long long) = %d\n", sizeof(long long)); //нельзя произвести вызов sizeof как оператора для имени типа //sizeof int - ошибка компиляции _getch(); }

В си один и тот же тип может иметь несколько названий
short === short int
long === long int
long long === long long int
unsigned int === unsigned

Типы с плавающей точкой

  • float - 4 байта,
  • long float - 8 байт
  • double - 8 байт
  • long double - 8 байт.
Здесь также приведены значения для VC2012, по стандарту размер типов float <= long float <= double <= long double все числа с плавающей точкой - со знаком.

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

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

#include #include void main() { unsigned a = 4294967295; int b = 2147483647; //Переполнение беззнакового типа printf("%u\n", a); a += 1; printf("%u", a); //Переполнение знакового типа printf("%d\n", b); b += 1; printf("%d", b); getch(); }

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

Постфиксное обозначение типа

П ри работе с числами можно с помощью литер в конце числа явно указывать его тип, например

  • 11 - число типа int
  • 10u - unsigned
  • 22l или 22L - long
  • 3890ll или 3890LL - long long (а также lL или Ll)
  • 80.0f или 80.f или 80.0F - float (обязательно наличие десятичной точки в записи)
  • 3.0 - число типа double
Экспоненциальная форма записи также по умолчанию обозначает число типа double. #include #include int main() { printf("sizeof(int) = %d\n", sizeof(10)); printf("sizeof(unigned) = %d\n", sizeof(10u)); printf("sizeof(long) = %d\n", sizeof(10l)); printf("sizeof(long long) = %d\n", sizeof(10ll)); printf("sizeof(float) = %d\n", sizeof(10.f)); printf("sizeof(double) = %d\n", sizeof(10.)); printf("sizeof(double) = %d\n", sizeof(10e2)); getch(); }

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

Int a = 10u; double g = 3.f;

Шестнадцатеричный и восьмеричный формат

В о время работы с числами можно использовать шестнадцатеричный и восьмеричный формат представления. Числа в шестнадцатиричной системе счисления начинаются с 0x, в восьмеричной системе с нуля. Соответственно, если число начинается с нуля, то в нём не должно быть цифр выше 7:

#include #include void main() { int x = 0xFF; int y = 077; printf("hex x = %x\n", x); printf("dec x = %d\n", x); printf("oct x = %o\n", x); printf("oct y = %o\n", y); printf("dec y = %d\n", y); printf("hex y = %x", y); getch(); }

Экспоненциальная форма представления чисел

Э кспоненциальной формой представления числа называют представление числа в виде M e ± p , где M - мантиса числа, p - степень десяти. При этом у мантисы должен быть один ненулевой знак перед десятичной запятой.
Например 1.25 === 1.25e0, 123.5 === 1.235e2, 0.0002341 === 2.341e-4 и т.д.
Представления 3.2435e7 эквивалентно 3.2435e+7
Существеут и другое представление ("инженерное"), в котором степень должна быть кратной тройке. Например 1.25 === 1.25e0, 123.5 === 123.5e0, 0.0002341 === 234.1e-6, 0.25873256 === 258.73256e-3 и т.д.

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

В си переменные объявляются всегда в начале блока (блок - участок кода,ограниченный фигурными скобками)

<возвращаемый тип> <имя функции> (<тип> <аргумент>[, <тип> <аргумент>]) { объявление переменных всё остальное }

При объявлении переменной пишется её тип и имя.

Int a; double parameter;

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

Long long arg1, arg2, arg3;

Например

#include #include int main() { int a = 10; int b; while (a>0){ int z = a*a; b += z; } }

Здесь объявлены переменные a и b внутри функции main , и переменная z внутри тела цикла. Следующий код вызовет ошибку компиляции

Int main() { int i; i = 10; int j; }

Это связано с тем, что объявление переменной стоит после оператора присваивания. При объявлении переменных можно их сразу инициализировать.
int i = 0;
При этом инициализация при объявлении переменной не считается за отдельный оператор, поэтому следующий код будет работать

Int main() { int i = 10; int j; }

Начальное значение переменной

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

#include #include int main() { int i; printf("%d", i); getch(); }

Если выполнять эту программу на VC, то во время выполнения вылетит предупреждение
Run-Time Check Failure #3 - The variable "i" is being used without being initialized.
Если нажать "Продолжить", то программа выведет "мусор". В многих других компиляторах при выполнении программы не будет предупреждения.

Область видимости переменной

П еременные бывают локальными (объявленными внутри какой-нибудь функции) и глобальными. Глобальная переменная видна всем функциям, объявленным в данном файле. Локальная переменная ограничена своей областью видимости. Когда я говорю, что переменная "видна в каком-то месте", это означает, что в этом месте она определена и её можно использовать. Например, рассмотрим программу, в которой есть глобальная переменная

#include #include int global = 100; void foo() { printf("foo: %d\n", global); } void bar(int global) { printf("bar: %d\n", global); } int main() { foo(); bar(333); getch(); }

Будет выведено
foo: 100
bar: 333
Здесь глобальная переменная global видна всем функциям. Но аргумент функции затирает глобальную переменную, поэтому при передаче аргумента 333 выводится локальное значение 333.
Вот другой пример

#include #include int global = 100; int main() { int global = 555; printf("%d\n", global); getch(); }

Программа выведет 555. Также, как и в прошлом случае, локальная переменная "важнее". Переменная, объявленная в некоторой области видимости не видна вне её, например

#include #include int global = 100; int main() { int x = 10; { int y = 30; printf("%d", x); } printf("%d", y); }

Этот пример не скомпилируется, потому что переменная y существует только внутри своего блока.
Вот ещё пример, когда переменные, объявленные внутри блока перекрывают друг друга

#include #include int global = 100; int main() { int x = 10; { int x = 20; { int x = 30; printf("%d\n", x); } printf("%d\n", x); } printf("%d\n", x); getch(); }

Программа выведет
30
20
10
Глобальных переменных необходимо избегать. Очень часто можно услышать такое. Давайте попытаемся разобраться, почему. В ваших простых проектах глобальные переменные выглядят вполне нормально. Но представьте, что у вас приложение, которое

  • 1) Разрабатывается несколькими людьми и состоит из сотен тысяч строк кода
  • 2) Работает в несколько потоков

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

Безусловно, есть ситуации, когда глобальные переменные упрощают программу, но такие ситуации случаются не часто и не в ваших домашних заданиях, так что НЕ СОЗДАВАЙТЕ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ!
Переменные могут быть не только целочисленными и с плавающей точкой. Существует множество других типов, которые мы будем изучать в дальнейшем.

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

Таблица 1 — Типы данных С++
Тип байт Диапазон принимаемых значений

целочисленный (логический) тип данных

bool 1 0 / 255

целочисленный (символьный) тип данных

char 1 0 / 255

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

short int 2 -32 768 / 32 767
unsigned short int 2 0 / 65 535
int 4
unsigned int 4 0 / 4 294 967 295
long int 4 -2 147 483 648 / 2 147 483 647
unsigned long int 4 0 / 4 294 967 295

типы данных с плавающей точкой

float 4 -2 147 483 648.0 / 2 147 483 647.0
long float 8
double 8 -9 223 372 036 854 775 808 .0 / 9 223 372 036 854 775 807.0

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

Тип данных bool

Первый в таблице — это тип данных bool целочисленный тип данных, так как диапазон допустимых значений — целые числа от 0 до 255. Но как Вы уже заметили, в круглых скобочках написано — логический тип данных, и это тоже верно. Так как bool используется исключительно для хранения результатов логических выражений. У логического выражения может быть один из двух результатов true или false . true — если логическое выражение истинно, false — если логическое выражение ложно.

Но так как диапазон допустимых значений типа данных bool от 0 до 255, то необходимо было как-то сопоставить данный диапазон с определёнными в языке программирования логическими константами true и false . Таким образом, константе true эквивалентны все числа от 1 до 255 включительно, тогда как константе false эквивалентно только одно целое число — 0. Рассмотрим программу с использованием типа данных bool .

// data_type.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; int main(int argc, char* argv) { bool boolean = 25; // переменная типа bool с именем boolean if (boolean) // условие оператора if cout << "true = " << boolean << endl; // выполнится в случае истинности условия else cout << "false = " << boolean << endl; // выполнится в случае, если условие ложно system("pause"); return 0; }

В строке 9 объявлена переменная типа bool , которая инициализирована значением 25. Теоретически после строки 9 , в переменной boolean должно содержаться число 25, но на самом деле в этой переменной содержится число 1. Как я уже говорил, число 0 — это ложное значение, число 1 — это истинное значение. Суть в том, что в переменной типа bool могут содержаться два значения — 0 (ложь) или 1 (истина). Тогда как под тип данных bool отводится целый байт, а это значит, что переменная типа bool может содержать числа от 0 до 255. Для определения ложного и истинного значений необходимо всего два значения 0 и 1. Возникает вопрос: «Для чего остальные 253 значения?».

Исходя из этой ситуации, договорились использовать числа от 2 до 255 как эквивалент числу 1, то есть истина. Вот именно по этому в переменной boolean содержится число 25 а не 1. В строках 10 -13 объявлен , который передает управление оператору в строке 11 , если условие истинно, и оператору в строке 13 , если условие ложно. Результат работы программы смотреть на рисунке 1.

True = 1 Для продолжения нажмите любую клавишу. . .

Рисунок 1 — Тип данных bool

Тип данных char

Тип данных char — это целочисленный тип данных, который используется для представления символов. То есть, каждому символу соответствует определённое число из диапазона . Тип данных char также ещё называют символьным типом данных, так как графическое представление символов в С++ возможно благодаря char . Для представления символов в C++ типу данных char отводится один байт, в одном байте — 8 бит, тогда возведем двойку в степень 8 и получим значение 256 — количество символов, которое можно закодировать. Таким образом, используя тип данных char можно отобразить любой из 256 символов. Все закодированные символы представлены в .

ASCII (от англ. American Standard Code for Information Interchange) - американский стандартный код для обмена информацией.

Рассмотрим программу с использованием типа данных char .

// symbols.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; int main(int argc, char* argv) { char symbol = "a"; // объявление переменной типа char и инициализация её символом "a" cout << "symbol = " << symbol << endl; // печать символа, содержащегося в переменной symbol char string = "сайт"; // объявление символьного массива (строки) cout << "string = " << string << endl; // печать строки system("pause"); return 0; }

Итак, в строке 9 объявлена переменная с именем symbol , ей присвоено значение символа "a" (ASCII код ). В строке 10 оператор cout печатает символ, содержащийся в переменной symbol . В строке 11 объявлен строковый массив с именем string , причём размер массива задан неявно. В строковый массив сохранена строка "сайт" . Обратите внимание на то, что, когда мы сохраняли символ в переменную типа char , то после знака равно мы ставили одинарные кавычки, в которых и записывали символ. При инициализации строкового массива некоторой строкой, после знака равно ставятся двойные кавычки, в которых и записывается некоторая строка. Как и обычный символ, строки выводятся с помощью оператора cout , строка 12 . Результат работы программы показан на рисунке 2.

Symbol = a string = сайт Для продолжения нажмите любую клавишу. . .

Рисунок 2 — Тип данных char

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

Целочисленные типы данных используются для представления чисел. В таблице 1 их аж шесть штук: short int , unsigned short int , int , unsigned int , long int , unsigned long int . Все они имеют свой собственный размер занимаемой памяти и диапазоном принимаемых значений. В зависимости от компилятора, размер занимаемой памяти и диапазон принимаемых значений могут изменяться. В таблице 1 все диапазоны принимаемых значений и размеры занимаемой памяти взяты для компилятора MVS2010. Причём все типы данных в таблице 1 расположены в порядке возрастания размера занимаемой памяти и диапазона принимаемых значений. Диапазон принимаемых значений, так или иначе, зависит от размера занимаемой памяти. Соответственно, чем больше размер занимаемой памяти, тем больше диапазон принимаемых значений. Также диапазон принимаемых значений меняется в случае, если тип данных объявляется с приставкой unsigned — без знака. Приставка unsigned говорит о том, что тип данных не может хранить знаковые значения, тогда и диапазон положительных значений увеличивается в два раза, например, типы данных short int и unsigned short int .

Приставки целочисленных типов данных:

short приставка укорачивает тип данных, к которому применяется, путём уменьшения размера занимаемой памяти;

long приставка удлиняет тип данных, к которому применяется, путём увеличения размера занимаемой памяти;

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

Так, что, по сути, мы имеем один целочисленный тип для представления целых чисел — это тип данных int . Благодаря приставкам short , long , unsigned появляется некоторое разнообразие типов данных int , различающихся размером занимаемой памяти и (или) диапазоном принимаемых значений.

Типы данных с плавающей точкой

В С++ существуют два типа данных с плавающей точкой: float и double . Типы данных с плавающей точкой предназначены для хранения чисел с плавающей точкой. Типы данных float и double могут хранить как положительные, так и отрицательные числа с плавающей точкой. У типа данных float размер занимаемой памяти в два раза меньше, чем у типа данных double , а значит и диапазон принимаемых значений тоже меньше. Если тип данных float объявить с приставкой long , то диапазон принимаемых значений станет равен диапазону принимаемых значений типа данных double . В основном, типы данных с плавающей точкой нужны для решения задач с высокой точностью вычислений, например, операции с деньгами.

Итак, мы рассмотрели главные моменты, касающиеся основных типов данных в С++. Осталось только показать, откуда взялись все эти диапазоны принимаемых значений и размеры занимаемой памяти. А для этого разработаем программу, которая будет вычислять основные характеристики всех, выше рассмотренных, типов данных.

// data_types.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include // библиотека манипулирования вводом/выводом #include // заголовочный файл математических функций #include using namespace std; int main(int argc, char* argv) { cout << " data type " << "byte" << " " << " max value " << endl // заголовки столбцов << "bool = " << sizeof(bool) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных bool*/ << (pow(2,sizeof(bool) * 8.0) - 1) << endl << "char = " << sizeof(char) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных char*/ << (pow(2,sizeof(char) * 8.0) - 1) << endl << "short int = " << sizeof(short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных short int*/ << (pow(2,sizeof(short int) * 8.0 - 1) - 1) << endl << "unsigned short int = " << sizeof(unsigned short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned short int*/ << (pow(2,sizeof(unsigned short int) * 8.0) - 1) << endl << "int = " << sizeof(int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных int*/ << (pow(2,sizeof(int) * 8.0 - 1) - 1) << endl << "unsigned int = " << sizeof(unsigned int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned int*/ << (pow(2,sizeof(unsigned int) * 8.0) - 1) << endl << "long int = " << sizeof(long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long int*/ << (pow(2,sizeof(long int) * 8.0 - 1) - 1) << endl << "unsigned long int = " << sizeof(unsigned long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных undigned long int*/ << (pow(2,sizeof(unsigned long int) * 8.0) - 1) << endl << "float = " << sizeof(float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных float*/ << (pow(2,sizeof(float) * 8.0 - 1) - 1) << endl << "double = " << sizeof(double) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных double*/ << (pow(2,sizeof(double) * 8.0 - 1) - 1) << endl; system("pause"); return 0; }

Данная программа выложена для того, чтобы Вы смогли просмотреть характеристики типов данных в своей системе. Не стоит разбираться в коде, так как в программе используются управляющие операторы, которые Вам, вероятнее всего, ещё не известны. Для поверхностного ознакомления с кодом программы, ниже поясню некоторые моменты. Оператор sizeof() вычисляет количество байт, отводимое под тип данных или переменную. Функция pow(x,y) возводит значение х в степень y , данная функция доступна из заголовочного файла . Манипуляторы fixed и setprecision() доступны из заголовочного файла . Первый — fixed , передаёт в поток вывода значения в фиксированной форме. Манипулятор setprecision(n) отображает n знаков после запятой. Максимальное значение некоторого типа данных вычисляется по такой формуле:

Max_val_type = 2^(b * 8 - 1) - 1; // для типов данных с отрицательными и положительными числами // где, b - количество байт выделяемое в памяти под переменную с таким типом данных // умножаем на 8, так как в одном байте 8 бит // вычитаем 1 в скобочках, так как диапазон чисел надо разделить надвое для положительных и отрицательных значений // вычитаем 1 в конце, так как диапазон чисел начинается с нуля // типы данных с приставкой unsigned max_val_type = 2^(b * 8) - 1; // для типов данных только с положительными числами // пояснения к формуле аналогичные, только в скобочка не вычитается единица

Пример работы программы можно увидеть на рисунке 3. В первом столбце показаны основные типы данных в С++, во втором столбце размер памяти, отводимый под каждый тип данных и в третьем столбце — максимальное значение, которое может содержать соответствующий тип данных. Минимальное значение находится аналогично максимальному. В типах данных с приставкой unsigned минимальное значение равно 0.

Data type byte max value bool = 1 255.00 char = 1 255.00 short int = 2 32767.00 unsigned short int = 2 65535.00 int = 4 2147483647.00 unsigned int = 4 4294967295.00 long int = 4 2147483647.00 unsigned long int = 4 4294967295.00 float = 4 2147483647.00 double = 8 9223372036854775808.00 Для продолжения нажмите любую клавишу. . .

Рисунок 3 — Типы данных С++

Если, например, переменной типа short int присвоить значение 33000, то произойдет переполнение разрядной сетки, так как максимальное значение в переменной типа short int это 32767. То есть в переменной типа short int сохранится какое-то другое значение, скорее всего будет отрицательным. Раз уж мы затронули тип данных int ,стоит отметить, что можно опускать ключевое слово int и писать, например, просто short . Компилятор будет интерпретировать такую запись как short int . Тоже самое относится и к приставкам long и unsigned . Например:

// сокращённая запись типа данных int short a1; // тоже самое, что и short int long a1; // тоже самое, что и long int unsigned a1; // тоже самое, что и unsigned int unsigned short a1; // тоже самое, что и unsigned short int

Последнее обновление: 13.11.2017

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

В языке C# есть следующие примитивные типы данных:

    bool : хранит значение true или false (логические литералы). Представлен системным типом System.Boolean

    Bool alive = true; bool isDead = false;

    byte : хранит целое число от 0 до 255 и занимает 1 байт. Представлен системным типом System.Byte

    Byte bit1 = 1; byte bit2 = 102;

    sbyte : хранит целое число от -128 до 127 и занимает 1 байт. Представлен системным типом System.SByte

    Sbyte bit1 = -101; sbyte bit2 = 102;

    short : хранит целое число от -32768 до 32767 и занимает 2 байта. Представлен системным типом System.Int16

    Short n1 = 1; short n2 = 102;

    ushort : хранит целое число от 0 до 65535 и занимает 2 байта. Представлен системным типом System.UInt16

    Ushort n1 = 1; ushort n2 = 102;

    int : хранит целое число от -2147483648 до 2147483647 и занимает 4 байта. Представлен системным типом System.Int32 . Все целочисленные литералы по умолчанию представляют значения типа int:

    Int a = 10; int b = 0b101; // бинарная форма b =5 int c = 0xFF; // шестнадцатеричная форма c = 255

    uint : хранит целое число от 0 до 4294967295 и занимает 4 байта. Представлен системным типом System.UInt32

    Uint a = 10; uint b = 0b101; uint c = 0xFF;

    long : хранит целое число от –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 и занимает 8 байт. Представлен системным типом System.Int64

    Long a = -10; long b = 0b101; long c = 0xFF;

    ulong : хранит целое число от 0 до 18 446 744 073 709 551 615 и занимает 8 байт. Представлен системным типом System.UInt64

    Ulong a = 10; ulong b = 0b101; ulong c = 0xFF;

    float : хранит число с плавающей точкой от -3.4*10 38 до 3.4*10 38 и занимает 4 байта. Представлен системным типом System.Single

    double : хранит число с плавающей точкой от ±5.0*10 -324 до ±1.7*10 308 и занимает 8 байта. Представлен системным типом System.Double

    decimal : хранит десятичное дробное число. Если употребляется без десятичной запятой, имеет значение от ±1.0*10 -28 до ±7.9228*10 28 , может хранить 28 знаков после запятой и занимает 16 байт. Представлен системным типом System.Decimal

    char : хранит одиночный символ в кодировке Unicode и занимает 2 байта. Представлен системным типом System.Char . Этому типу соответствуют символьные литералы:

    Char a = "A"; char b = "\x5A"; char c = "\u0420";

    string : хранит набор символов Unicode. Представлен системным типом System.String . Этому типу соответствуют символьные литералы.

    String hello = "Hello"; string word = "world";

    object : может хранить значение любого типа данных и занимает 4 байта на 32-разрядной платформе и 8 байт на 64-разрядной платформе. Представлен системным типом System.Object , который является базовым для всех других типов и классов.NET.

    Object a = 22; object b = 3.14; object c = "hello code";

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

Using System; namespace HelloApp { class Program { static void Main(string args) { string name = "Tom"; int age = 33; bool isEmployed = false; double weight = 78.65; Console.WriteLine($"Имя: {name}"); Console.WriteLine($"Возраст: {age}"); Console.WriteLine($"Вес: {weight}"); Console.WriteLine($"Работает: {isEmployed}"); } } }

Для вывода данных на консоль здесь применяется интерполяция: перед строкой ставится знак $ и после этого мы можем вводить в строку в фигурных скобках значения переменных. Консольный вывод программы:

Имя: Tom Возраст: 33 Вес: 78,65 Работает: False

Использование суффиксов

При присвоении значений надо иметь в виду следующую тонкость: все вещественные литералы рассматриваются как значения типа double . И чтобы указать, что дробное число представляет тип float или тип decimal , необходимо к литералу добавлять суффикс: F/f - для float и M/m - для decimal.

Подобным образом все целочисленные литералы рассматриваются как значения типа int . Чтобы явным образом указать, что целочисленный литерал представляет значение типа uint, надо использовать суффикс U/u , для типа long - суффикс L/l , а для типа ulong - суффикс UL/ul :

Uint a = 10U; long b = 20L; ulong c = 30UL;

Использование системных типов

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

Int a = 4; System.Int32 b = 4;

Неявная типизация

Ранее мы явным образом указывали тип переменных, например, int x; . И компилятор при запуске уже знал, что x хранит целочисленное значение.

Однако мы можем использовать и модель неявной типизации:

Var hello = "Hell to World"; var c = 20; Console.WriteLine(c.GetType().ToString()); Console.WriteLine(hello.GetType().ToString());

Для неявной типизации вместо названия типа данных используется ключевое слово var . Затем уже при компиляции компилятор сам выводит тип данных исходя из присвоенного значения. В примере выше использовалось выражение Console.WriteLine(c.GetType().ToString()); , которое позволяет нам узнать выведенный тип переменной с. Так как по умолчанию все целочисленные значения рассматриваются как значения типа int , то поэтому в итоге переменная c будет иметь тип int или System.Int32

Эти переменные подобны обычным, однако они имеют некоторые ограничения.

Во-первых, мы не можем сначала объявить неявно типизируемую переменную, а затем инициализировать:

// этот код работает int a; a = 20; // этот код не работает var c; c= 20;

Во-вторых, мы не можем указать в качестве значения неявно типизируемой переменной null:

// этот код не работает var c=null;

Так как значение null, то компилятор не сможет вывести тип данных.

double или decimal

Из выше перечисленного списка типов данных очевидно, что если мы хотим использовать в программе числа до 256, то для их хранения мы можем использоват переменные типа byte . При использовании больших значений мы можем взять тип short, int, long. То же самое для дробных чисел - для обычных дробных чисел можно взять тип float, для очень больших дробных чисел - тип double. Тип decimal здесь стоит особняком в том плане, что несмотря на большую разрядность по сравнению с типом double, тип double может хранить большее значение. Однако значение decimal может содержать до 28 знаков после запятой, тогда как значение типа double - 15-16 знаков после запятой.

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