Skip to content

Latest commit

 

History

History
118 lines (90 loc) · 8.21 KB

File metadata and controls

118 lines (90 loc) · 8.21 KB

Лекция 2 — 14.01.2022

Статическая / динамическая типизация

  • Статистическая — типы известны до компиляции. Позволяет компилятору производить хитрые оптимизации; пример: С++.
  • Динамическая — типы не известны до компиляции; пример: Питон.

Сильная / слабая типизация

  • Сильная — нельзя неявно преобразовывать в другой тип; пример: Java.
  • Слабая — можно неявно преобразовывать типы данных; пример: JavaScript (1 + ‘1’ = 2).

Типы данных

  • void — не хранит ничего, можно использовать как тип данных для функций, которые ничего не возвращают;

  • bool — 2 литерала, true,false;

    • К bool неявно приводятся и целочисленные значения (0, 1);
    • Занимает не 1 бит, а как минимум 1 байт;
    🧷 Литералы — конструкции языка; а `std` стандартная библиотека — отдельная категория, не обычные конструкции языка.
  • char — в одинарных кавычках, написать в них несколько символов нельзя;

    • Имеет размер 1 байта;
    • Стандарт не гарантирует, знаковый он или нет (зависит от платформы реализации);
    • Явно беззнаковый: unsigned char (от 0 до 255 бит) и явно знаковый: signed char (от -128 до 127);
1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)  // по стандарту
  • Численные типы данных:
    • int — целые числа, по умолчанию знаковый;
      • По стандарту не имеет явного размера;
      • Стандарт говорит, что размер int будет ≥ 16 бит;
    • short (int) — размер меньше int, ≥ 16 бит;
    • long (int) — размер ≥ 32 бита;
    • long long (int) — размер ≥ 64 бит
    • Если напишем ключевое слово unsigned — будет беззнаковый тип;
    • Знаковые и беззнаковые типы — разные (не модификация одного и того же);
    • Размер беззнакового типа всегда равен размеру соответствующему ему знаковому типу;
    • float и double — формат и диапазон значений не специфицирован стандартом, числа с плавающей запятой;
      • Не вещественное число, а дробное, которое аппроксимирует вещественное, так как оно должно быть конечным в памяти (нельзя закодировать произвольное);
      • Экспоненциальная форма записи числа:
        • $0.123 \cdot 2^{456}$ — мантисса и экспонента;
        • В памяти выделяется несколько бит под мантиссу и несколько под экспоненту;
        • В double существует два значения 0;
        • Например, число 10 не представляется как аппроксимация 9,9... — самое близкое число, которое можно записать с помощью степени 2;
        • У double неравномерная точность, так как при превышении мантиссы начинает расти экспонента, а она уже существенно увеличивает число;
        • Два double с друг с другом нельзя сравнивать через = , так как это аппроксимации и может возникать разная ошибка округления;
          • Надо сравнивать по модулю маленькой $\varepsilon$ их разность;

Операции с типами данных

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

    std::cout << std::numeric_limits<unsigned int>::max << std::endl;
  • Размер объекта:

    sizeof(object) // настоящий оператор, выдаёт ответ в битах
  • Хранение знаковых / беззнаковых типов данных в памяти — с помощью дополнения до 2 (инвертирование значения всех бит);

  • 0 кодируется единственным способом;

  • unsigned — используется, когда значение физически не будет отрицательным (размер выделенной памяти);

  • Сравнение знаковых и беззнаковых типов:

    • Надо привести к одному типу;
    • Так как в памяти signed выглядит как unsigned, то никакого реального преобразования не происходит;
  • % — взятие остатка по модулю;

  • += / -= / *= / /= / %= — инкрементные операции;

  • ± — унарные операции (положительные/отрицательные);

  • Логические операции:

    • Побитовые:
      • Проводят операции с int
      • | — побитовое „или“;
      • & — побитовое „и“;
      • ^ — побитовый „xor“ (исключающее или);
    • Логические:
      • && — логическое „и“ (типы данных приводятся к bool — ненулевые значения приводятся к true, нулевые — false)
      • || — логическое „или“;
      • К bool можно применять и арифметические операторы, но лучше писать логические операторы, чтобы было понятно, что мы имеем ввиду логическую семантику;

Переполнения типов

  • У беззнаковых типов при переполнении числа будут выдавать значения по модулю 2;
for (unsigned int i = 10, i >= 0, --i) {
	std:: cout << i << std:endl;  // выдаст большие значения, так как происходит переполнение
} // это происходит, так как unsigned не может быть меньше нуля

Undefined behaviour

  • Если мы не напишем по стандарту, то программа может начать вести себя „странно“, однако любое такое нестандартное поведение будет валидно по стандарту;

Литералы

  • Можно писать в двоичном или шестнадцетиричном формате;
int a = 1u; // u в конце гарантирует unsigned тип
double d = 0.1e1000; // можно написать числа с помощью экспоненциального формата

Переменные

  • Синтаксис C++ разрешает писать несколько переменных в одной строке, но этим лучше не пользоваться, так как приводит к ошибкам:
int a, b = 0; // здесь лишь b будет равно нулю