Функция в C++ — фрагмент программного кода, к которому можно обратиться из другого места программы.

У функции, чаще всего, имеется имя, тело и параметры.

С именем функции неразрывно связан адрес первой инструкции в теле функции, которой передаётся управление при обращении к функции. После выполнения функции управление возвращается обратно в точку программы, откуда данная функция была вызвана.

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

Пример объявления функции:

Тип_функции Имя_функции (Список_параметров) {

    Тело функции

}

Тип функции — это тип возвращаемого функцией значения.

Список параметров функции —  это объявление переменных для передачи через них значений в тело функции.

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

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

int umnominus(int x, int y, int z){
  int l = x * y - z;
  return l;
}

void setup() {
  Serial.begin(9600);
  Serial.print(umnominus(4, 1, 100));

}

void loop() {

}

Лист. 1. Создана функция umnominus().

int area(int a, int b){
  return a * b;
}

void setup() {
  Serial.begin(9600);
  Serial.print(area(3, 5));
}

void loop() {

}

Лист. 2. Создана функция area() для вычисления площади прямоугольника.

float area(int a, int b){
  return a * b / 2;
}

void setup() {
  Serial.begin(9600);
  Serial.print(area(3, 5));
}

void loop() {

}

Лист. 3. Создана функция area() для вычисления площади треугольника.

Функция area() в примере листинг 3 вычисляет площадь треугольника с погрешностью. Причём, эту погрешность вычислений мы можем заметить только если произведение параметров a и b нечётное.

float area(int a, float b){
  return a * b / 2;
}

void setup() {
  Serial.begin(9600);
  Serial.print(area(3, 5));
}

void loop() {

}

Лист. 4. Создана функция area() для вычисления площади треугольника.

float area(int a, int b){
  return a * b / 2.0;
}

void setup() {
  Serial.begin(9600);
  Serial.print(area(3, 5));
}

void loop() {

}

Лист. 5. Создана функция area() для вычисления площади треугольника.

Функция определяет собственную (локальную) область видимости, куда входят входные параметры, а также те переменные, которые объявляются непосредственно в теле самой функции.

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

Вычисление факториала

апрвапр

Рис. 1.

jhfjh

unsigned long factorial(int a){
  unsigned long f = 1;
  for(int n = 1; n <= a; n++)
    f *= n;
  return f;
}

void setup() {
  Serial.begin(9600);
  Serial.println(factorial(12));
}

void loop() {

}

Лист. 6.

unsigned long factorial(int a){
  if(a==1) return 1;
  return a * factorial(a-1);
}

void setup() {
  Serial.begin(9600);
  Serial.println(factorial(12));
}

void loop() {

}

Лист. 7.

Conway's Game of Life

Воспользуемся примером из библиотеки MaxAndMatrix для создания игры Жизнь на светодиодной матрице 8х8.

#include "MaxAndMatrix.h"

int dataPin = 12;                // DIN
int clockPin = 11;               // CLK
int csPin = 10;                  // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);

byte matrix[8] = {0b01110001,
                  0b11011011,
                  0b10001110,
                  0b10001100,
                  0b10001000,
                  0b11111111,
                  0b10000001,
                  0b11111111
                 };

void setup() {
  led88.begin(0);
  led88.force(0);
  led88.loadMatrix(matrix);
}

void loop() {

}

Лист. 8. Пример из библиотеки MaxAndMatrix

Рис. 1. Принципиальная электрическая схема LED дисплея 8x8 с микросхемой MAX7219 управляемого микроконтроллером ATtiny88.

#include "MaxAndMatrix.h"

int dataPin = 12;                // DIN
int clockPin = 11;               // CLK
int csPin = 10;                  // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);

byte matrix[8] = {0b00011000,
                  0b00100100,
                  0b01000010,
                  0b10000001,
                  0b10000001,
                  0b01000010,
                  0b00100100,
                  0b00011000
                 };
byte conways[64];

void setup() {
  led88.begin(0);
  led88.force(4);
  for(int i=0; i<64; i++){
    conways[i] = (matrix[i/8] & 1<<(i%8)) == 0 ? 0 : 1;
  }
}

void loop() {

}

Лист. 9. Преобразование массива в массив.

#include "MaxAndMatrix.h"

int dataPin = 12;                // DIN
int clockPin = 11;               // CLK
int csPin = 10;                  // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);

byte matrix[8] = {0b00011000,
                  0b00100100,
                  0b01000010,
                  0b10000001,
                  0b10000001,
                  0b01000010,
                  0b00100100,
                  0b00011000
                 };
byte conways[64];

void setup() {
  led88.begin(0);
  led88.force(4);
  for(int i=0; i<64; i++){
    conways[i] = (matrix[i/8] & 1<<(i%8)) == 0 ? 0 : 1;
  }
}

void loop() {
  toled();
  delay(200);
}

void toled(){
  byte matrix[8] {0,0,0,0,0,0,0,0};
  for(int i=0; i<64; i++)
    matrix[i/8] |= conways[i] << (i % 8);
  led88.loadMatrix(matrix);
}

Лист. 10. Преобразование массива в массив и вывод на матрицу.

#include "MaxAndMatrix.h"

int dataPin = 12;                // DIN
int clockPin = 11;               // CLK
int csPin = 10;                  // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);

byte matrix[8] = {0b00011000,
                  0b00100100,
                  0b01000010,
                  0b10000001,
                  0b10000001,
                  0b01000010,
                  0b00100100,
                  0b00011000
                 };
byte conways[64];

void setup() {
  Serial.begin(9600);
  led88.begin(0);
  led88.force(4);
  for(int i=0; i<64; i++){
    conways[i] = (matrix[i/8] & 1<<(i%8)) == 0 ? 0 : 1;
  }
  for(int i=0; i<64; i++){
    Serial.print(romie(i));
  }
}

void loop() {
  toled();
  delay(200);
}

int romie(int n){
    int m = 0;
    for(int i=-8; i<=8; i+=8)
      for(int j=-1; j<=1; j++)
        if((n+i+j >= 0 and n+i+j < 64 and (n+i)/8 == (n+i+j)/8) and n+i+j != n)
          m += conways[i + j + n];
    return m;
}

void toled(){
  byte matrix[8] {0,0,0,0,0,0,0,0};
  for(int i=0; i<64; i++)
    matrix[i/8] |= conways[i] << (i % 8);
  led88.loadMatrix(matrix);
}

Лист. 11. Создана функция romie() 

#include "MaxAndMatrix.h"

int dataPin = 12;                // DIN
int clockPin = 11;               // CLK
int csPin = 10;                  // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);

byte matrix[8] = {0b00011000,
                  0b00100100,
                  0b01000010,
                  0b10000001,
                  0b10000001,
                  0b01000010,
                  0b00100100,
                  0b00011000
                 };
byte conways[64];

void setup() {
  led88.begin(0);
  led88.force(4);
  for(int i=0; i<8; i++){
    for(int j=0; j<8; j++){
      conways[i*8+j] = (matrix[i] & 1<<j) == 0 ? 0 : 1;
    }
  }
}

void loop() {
  toled();
  live();
  delay(200);
}

void live(){
  byte next[64];
  for(int n=0; n<64; n++){
    next[n] = 0;
    int m = romie(n);
    if(m == 3)
      next[n] = 1;
    else if(m == 2)
      next[n] = conways[n];
  }
  for(int i=0; i<64; i++)
    conways[i] = next[i];
}

int romie(int n){
    int m = 0;
    for(int i=-8; i<=8; i+=8)
      for(int j=-1; j<=1; j++)
        if((n+i+j >= 0 and n+i+j < 64 and (n+i)/8 == (n+i+j)/8) and n+i+j != n)
          m += conways[i + j + n];
    return m;
}

void toled(){
  byte matrix[8] {0,0,0,0,0,0,0,0};
  for(int i=0; i<64; i++)
    matrix[i/8] |= conways[i] << (i % 8);
  led88.loadMatrix(matrix);
}

Лист. 12. Игра «Жизнь» (англ. Game of Life) — клеточный автомат Джона Конвея (John Horton Conway 26 December 1937 – 11 April 2020).

#include "MaxAndMatrix.h"

int dataPin = 12;                // DIN
int clockPin = 11;               // CLK
int csPin = 10;                  // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);

// Салют
//byte matrix[8] = {0b00011000,
//                  0b00100100,
//                  0b01000010,
//                  0b10000001,
//                  0b10000001,
//                  0b01000010,
//                  0b00100100,
//                  0b00011000
//                 };

// Маленькие часики
//byte matrix[8] = {0b00000000,
//                  0b00000000,
//                  0b00001000,
//                  0b00101000,
//                  0b00010100,
//                  0b00010000,
//                  0b00000000,
//                  0b00000000
//                 };

// Лягушка
//byte matrix[8] = {0b00000000,
//                  0b00000000,
//                  0b00000000,
//                  0b00011100,
//                  0b00111000,
//                  0b00000000,
//                  0b00000000,
//                  0b00000000
//                 };

// Змея
//byte matrix[8] = {0b11000000,
//                  0b10100000,
//                  0b00000000,
//                  0b00101000,
//                  0b00000000,
//                  0b00001010,
//                  0b00000001,
//                  0b00000011
//                 };

// Указатель
//byte matrix[8] = {0b00000000,
//                  0b00000000,
//                  0b00110000,
//                  0b00110000,
//                  0b00001100,
//                  0b00001100,
//                  0b00000000,
//                  0b00000000
//                 };

// Муравей
//byte matrix[8] = {0b00001000,
//                  0b00101000,
//                  0b01000010,
//                  0b10111100,
//                  0b01000010,
//                  0b00101000,
//                  0b00001000,
//                  0b00000000
//                 };

// Скорпион
//byte matrix[8] = {0b00010000,
//                  0b00010100,
//                  0b01000000,
//                  0b00111110,
//                  0b01000000,
//                  0b00010100,
//                  0b00010000,
//                  0b00000000
//                 };

// Часы
//byte matrix[8] = {0b10110110,
//                  0b11010100,
//                  0b00010010,
//                  0b11000110,
//                  0b10010000,
//                  0b01010110,
//                  0b11011010,
//                  0b00000000
//                 };

// Медуза
//byte matrix[8] = {0b01100000,
//                  0b10010000,
//                  0b10101000,
//                  0b01001110,
//                  0b00000000,
//                  0b00011000,
//                  0b00010000,
//                  0b00000000
//                 };

// Осьминог
byte matrix[8] = {0b00000000,
                  0b00000000,
                  0b00011000,
                  0b00100100,
                  0b00111100,
                  0b10100101,
                  0b11000011,
                  0b00000000
                 };

byte conways[64];

void setup() {
  led88.begin(0);
  led88.force(4);
  for(int i=0; i<8; i++){
    for(int j=0; j<8; j++){
      conways[i*8+j] = (matrix[i] & 1<<j) == 0 ? 0 : 1;
    }
  }
  toled();
  delay(3000);
}

void loop() {
  toled();
  live();
  delay(200);
}

void live(){
  byte next[64];
  for(int n=0; n<64; n++){
    next[n] = 0;
    int m = romie(n);
    if(m == 3)
      next[n] = 1;
    else if(m == 2)
      next[n] = conways[n];
  }
  for(int i=0; i<64; i++)
    conways[i] = next[i];
}

int romie(int n){
    int m = 0;
    for(int i=-8; i<=8; i+=8)
      for(int j=-1; j<=1; j++)
        if((n+i+j >= 0 and n+i+j < 64 and (n+i)/8 == (n+i+j)/8) and n+i+j != n)
          m += conways[i + j + n];
    return m;
}

void toled(){
  byte matrix[8] {0,0,0,0,0,0,0,0};
  for(int i=0; i<64; i++)
    matrix[i/8] |= conways[i] << (i % 8);
  led88.loadMatrix(matrix);
}

Лист. 13. Игра «Жизнь» (англ. Game of Life) — клеточный автомат Джона Конвея с примерами

Не обязательные параметры

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

Например,

void setup() {
  Serial.begin(115200);
}

void loop() {
  fn(7);
}

void fn(int x = 4) {
  Serial.println(x * 2);
}

Лист. 14.

error: 'fn' was not declared in this scope
   fn(7);
   ^~
exit status 1
'fn' was not declared in this scope

Лист. 15.

Прототипы функций

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

void fn(int x=4);

void setup() {
  Serial.begin(115200);
}

void loop() {
  fn(7);
}

void fn(int x) {
  Serial.println(x * 2);
}

Лист. 16.

Перегрузка функций

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

int a = 10;
int b = 5;
float c = 10.0;

void summator(int x, int y) {
  Serial.println(x + y);
}

void summator(int x, float y) {
  Serial.println(x * y);
}

void setup() {
  Serial.begin(9600);
  summator(a, b);
  summator(b, c);
}

void loop() {
}

Лист. 17.