Вот у нас есть код, но он ничего не делает.
Начать знакомство, думаю, стоит с переменных - чтобы потом было с чем работать.
В языке есть встроенные типы переменных (char, int, short,long и т.д.), но я предпочитаю их не использовать ввиду того, что их размер в памяти не очевиден. Есть замечательная библиотечка stdint.h, в которой перечислены типы конкретных размеров и свойств - а в каждом компиляторе они пересчитываются в стандартные типы нужной размерности. Вот самые такие из них:
Тип | Размер (бит) | Знак? | Описание |
uint8_t | 8 | нет | Может хранить числа от 0 до 255. |
int8_t | 8 | да | Может хранить числа от -128 до 127. |
uint16_t | 16 | нет | Может хранить числа от 0 до 65 535. |
int16_t | 16 | да | Может хранить числа от -32 768 до 32 767. |
uint32_t | 32 | нет | Может хранить числа от 0 до 4 294 967 295. |
int32_t | 32 | да | Может хранить числа от 0 до -2 147 483 648 до 2 147 483 647. |
char | 8 | * | Используется для хранения однобайтных символов (character). |
* Зависит от компилятора
Объявление переменных выглядит следующим образом: <тип> <название переменной>;
Напимер:
uint8_t somevar; // Здесь будет храниться 8битное беззнаковое число
uint8_t varno2; // Ещё одно
char nya; // Здесь будем хранить символ какой-либо
Желательно переменные объявлять в начале блока — то естьчтоб перед ними была открывающая фигурная скобка и ничего более. Это уточним в примерах позднее.
Самое такое важное, наверное, — это оператор присваивания. То есть мы можем присвоить переменной какое-то значение. Числом ли, каким-то расчётом или из другой переменной —всё равно. Например:
somevar = 0; // Теперьв somevar записан 0.
varno2 = somevar; // В varno2 тоже. Они одного типа, всё хорошо.
nya = -2;
Вы можете без опасений присваивать переменные одинакового типа (одного размера и наличия знакового разряда), в остальных случаях стоит знать, что вы делаете и зачем. Это пойдёт отдельной заметкой о преобразовании типов. Числа можно представлять аж в трёх разрядностях: десятичной, шестнадцатиричной и восьмеричной.
Записывается это так.
Разрядность | Префикс | Пример |
8 | 0 | 01, 0777, 0234. |
10 | | 0, 1, 1234, 999. |
16 | 0x | 0xFF, 0x1234, 0x44. |
В компиляторе gcc есть поддержка двоичной разрядности: 0b11010101, но лучше это не использовать. И да, всегда перед использованием значения переменной убедитесь, что вы записали туда что либо. Иначе никто не поручится, что код будет работать правильно. Вот тут уже и можно кое-что попробовать.
Для начала посмотрим, какие есть в языке логические и математические операторы:
Оператор | Описание | Пример |
X + Y | Сложение. | somevar + 1 |
X - Y | Вычитание. | 3 - 1 |
X * Y | Умножение1. | somevar * 4 |
X / Y | Деление1. | somevar / 4 |
X % Y | Остаток от деления1. | somevar % 1 |
X | Y | Логическое ИЛИ2 (OR). | somevar | 0xF0 |
X & Y | Логическое И2 (AND). | somevar & 0x0F |
X ^ Y | Логическое исключающее ИЛИ2 (XOR). | somevar ^ 0x55 |
-X | Изменение знака числа (0 - X). | -nya |
~X | Инвертирование всех бит числа2 (NOT). | ~somevar |
1) Остерегайтесь использовать подобные операциина платформах, где их нет в наборе инструкций - это всё выльется в большой идолгий цикл.
2) Остерегайтесь применять логические операции на знаковых типах.
Операции можно комбинировать почти как угодно. Все они имеют свой приоритет, который похож на математический. Круглыми скобочками можно его поменять как угодно. Пример:
varno2 = somevar + 3 * 4; // Сначала умножится 3 на 4, потом уже прибавится
varno2 = (somevar + 3) * 4; // Сначала будет сложение, потом умножение
А ещё операции можно комбинировать с присваиванием, если один из операторов и результат – одна и та же переменная:
a = a + 2; // Эта и следующая операция делают одно и то же
a += 2;
a = a << 1; // То же самое с другим оператором
a <<= 1;
Пример кода со всем этим богатством:
#include
void main(void)
{
uint8_t a, b, c; // Три беззнаковых однобайтовых переменных
uint16_t d; // Двухбайтовая переменная
a = 0; // Присваивание
b = 0x11;
c = ~b; // Теперь в c хранится 0xEE
a += 10; // В a сидит 10
a *= 2; // В а сидит 20
b = c & 3; // В b сидит 2 (0xEE & 3 = 0b11101110 & 0b00000011 = 0b10 = 2)
a = 255; // В а 255 - самое большое число, вмещающееся в эту переменную
d = 255; // В d 255 - не самое большое число.
a++; // прибавили 1 - теперь там сидит 0. Старший разряд не влез.
d++; // прибавили 1 - теперь там сидит 256. Старший разряд перелез во второй байт.
}
А вот так делать не стоит:
#include
void main(void)
{
uint8_t a, b, c; // Три беззнаковых однобайтовых переменных
a = 0; // А инициализировали, а про b забыли...
// В b теперь может быть всё что угодно.
c = a + b; // Теперь в c хранится фиг знает что.
}