Описание языка С++ в AgavaSCADA/AgavaPLC

Материал из docs.kb-agava.ru
Перейти к навигации Перейти к поиску

Данное описание содержит базовое руководство по созданию программ на языке С++ и их интеграции в среду разработки.

Скрипты создаются в операциях «Скрипт С++».

1 Основы синтаксиса

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

int x;
x = 1;
int y = x + 2;

Для повышения удобства работы с кодом можно оставлять в нем комментарии, которые не задействуются при работе программы и предназначены для улучшения читаемости кода. Перед комментариями ставится «//»:

bool x = true;
// bool x = false;
// вторая строка не будет выполняться в программе

2 Переменные

Переменные – объекты, хранящиеся в памяти, над которыми и производятся действия в программе.

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

bool a = true;
int b = 1;
double c = 1.1;
string d = “строка”;

int f; // переменная инициализирована, значение не присвоено
f = 1; // присвоение значения

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

auto a = true;
auto b = 1;

2.1 Строки

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

При работе со строками доступны следующие функции:

Функция Действие
length () Возвращает длину строки
resize(uint) Устанавливает длину строки
isEmpty() Возвращает истину, если строка пуста, т. е. длина равна нулю
substr(uint start = 0, int count = -1) Возвращает строку с содержимым, начинающимся с start, и количеством байтов, заданным параметром count. Аргументы по умолчанию вернут всю строку как новую строку
insert(uint pos, const string &in other) Вставляет другую строку string на позиции pos в исходной строке
erase(uint pos, int count = -1) Удаляет количество символов count из строки, начиная с позиции pos
findFirst(const string &in str, uint start = 0) Находит первое вхождение значения str в строке, начиная с символа под номером start. Если вхождения не найдено, будет возвращено отрицательное значение
findLast(const string &in str, int start = -1) Находит последнее вхождение значения str в строке

Пример работы с функциями для строк:

string str = “ABCDEF”;          // инициализирована строка str
int a = str.length();           // a равно 6
int b = str.find
First(“CD”, 0); // b равно 2
string str1 = str.erase(1, 3);  // str1 равно “AEF”

2.2 Массивы

Массив — свокупный тип данных, который позволяет получить доступ ко всем переменным одного и того же типа данных через использование одного идентификатора. Используется в том случае, если вам необходимо сгруппировать несколько элементов одного типа:

array <int> a = {2, 5, 10, 15, 20};  // инициализирован массив a с пятью элементами
int x = a [0];       // x становится равен элементу массива а под номером 0 (2)
int y = a [4];       // y становится равен элементу массива а под номером 4 (20)
arr [3] = 11;        // элемент массива а под номером 3 становится равен 11
int z = arr [3];      // z становится равен элементу массива а под номером 3 (11)

Важно помнить, что нумерация членов массива начинается с 0.

При работе с массивами доступны следующие функции:

Функция Действие
length() Возвращает длину массива
resize(uint) Устанавливает новую длину массива
reverse() Меняет порядок элементов в массиве на обратный
insertAt(uint index, const T& in value) Вставляет новый элемент в массив по указанному индексу
insertLast(const T& in) Добавляет элемент в конец массива
removeAt(uint index) Удаляет элемент по указанному индексу
removeLast() Удаляет последний элемент массива
removeRange(uint start, uint count) Удаляет количество элементов count, начиная с элемента номер start
sortAsc () Сортирует элементы в массиве в порядке возрастания
sortDesc () Сортирует элементы в массиве в порядке убывания
find (const T &in) Возвращает индекс первого элемента, который имеет то же значение, что и желаемое. Если совпадений не найдено, возвращает отрицательное значение

Пример работы с функциями для массивов:

  int main()
  {
    array<int> arr = {1,2,3}; // 1,2,3
    arr.insertLast(0);        // 1,2,3,0
    arr.insertAt(2,4);        // 1,2,4,3,0
    arr.removeAt(1);          // 1,4,3,0
    arr.sortAsc();            // 0,1,3,4
    int sum = 0;

    for( uint n = 0; n < arr.length(); n++ )
      sum += arr[n];

    return sum;
  }

2.3 Перечисления

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

Значения перечислений объявляются путем их объявления в операторе перечисления. Если для константы перечисления не указано конкретное значение, она будет принимать значение предыдущей константы плюс 1. Первая константа получит значение 0, если не указано иное.

enum Errors
{
    NoError,         // = 0
    ReadError = 2,    // = 2
    WriteError,       // = 3
}

// теперь к константам перечисления можно обращаться через текстовое значение, например
// int a = NoError;

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

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

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

Тип Мин. значение Макс. значение
bool false (0) true (1)

Целочисленные переменные

Тип Мин. значение Макс. значение
int8 - 128 127
int16 - 32 768 32 767
int - 2 147 483 648 2 147 483 647
int64 - 9 223 372 036 854 775 808 9 223 372 036 854 775 807
uint8 0 255
uint16 0 65 535
uint 0 4 294 967 295
uint64 0 18 446 744 073 709 551 615

Переменные с плавающей запятой

Тип Диапазон значений Наименьшее значение
float ± 3.402823466 e+38 1.175494351 e-38
double ± 1.79769313486231 e+308 2.22507385850720 e-308

3 Операции

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

Операторы сравнения

Оператор Символ Пример Операция
Равно == x == y true, если x равно y
Не равно != x != y true, если x не равно y
Меньше < x < y true, если x меньше y
Больше > x > y true, если x больше y
Меньше или равно <= x <= y true, если x меньше или равно y
Больше или равно >= x >= y true, если x больше или равно y

Логические операторы

Оператор Символ Пример Операция
Логическое НЕ ! !x true, если x – false и false, если x – true
Логическое И && x && y true, если x и y – true, в противном случае – false
Логическое ИЛИ || x || y true, если x или y – true, в противном случае – false
Логическое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) ^ x ^ y true, если x или y – true (но не одновременно), в противном случае – false

Побитовые операторы

Оператор Символ Пример Операция
Побитовое И & x & y Каждый бит в x И каждый соответствующий ему бит в y
Побитовое ИЛИ | x | y Каждый бит в x ИЛИ каждый соответствующий ему бит в y
Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) ^ x ^ y Каждый бит в x XOR с каждым соответствующим ему битом в y
Побитовый сдвиг влево << x << y Все биты в x смещаются влево на y бит
Побитовый сдвиг вправо >> x >> y Все биты в x смещаются вправо на y бит

Арифметические операторы

Оператор Символ Пример Операция
Сложение + x + y Складываем x и y
Вычитание - x – y Вычитаем y из x
Умножение * x * y Умножаем x на y
Деление / x / y Делим x на y
Присваивание = x = y Присваиваем значение y переменной x
Сложение с присваиванием += x += y Добавляем y к x
Вычитание с присваиванием -= x -= y Вычитаем y из x
Умножение с присваиванием *= x *= y Умножаем x на y
Деление с присваиванием /= x /= y Делим x на y

Операторы приращений

Операция инкремента увеличивает значение на 1, декремента – уменьшает на 1.

Оператор Символ Пример Операция
Преинкремент ++ ++х Инкремент х, затем вычисление х
Предекремент -- --х Декремент х, затем вычисление х
Постинкремент ++ х++ Вычисление х, затем инкремент х
Постдекремент -- х-- Вычисление х, затем декремент х

Оператор индексации

Используется для доступа к элементу.

Оператор Символ Пример Операция
Индексация [ ] arr [0] Обращение к нулевому элементу массива arr

4 Блоки выражений и область видимости переменных

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

Внешние блоки не имеют доступа к переменным внутренних блоков.

{
    int a;
    float b;
    {
      float a = 1.0; // Отменить объявление внешней переменной
                     // но только в пределах внутреннего блока
      b = a;         // переменные из внешних блоков все еще доступны
      int c;
    }

    // a снова становится целочисленной переменной, b теперь равна 1.0, c здесь недоступна
  }

5 Условия

5.1 Операторы if/else

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

if ( x == 1 )
{
  // эти действия выполнятся, если х равно 1
}
else 
{
  // эти действия выполнятся, если х не равно 1
}

5.2 Условное выражение

Более короткая запись оператора выбора if/else:

x = 1 ? y = true : y = false;

// если х равно 1, тогда y равен true, иначе y равен false

5.3 Оператор switch

Является альтернативой if/else для тех случаев, когда необходимо сделать множественный выбор:

switch( x )
{
  case 0:
    // эти действия выполнятся, если х равно 0
    break;  // каждый case всегда должен заканчивать оператором break
  case 1:
    // эти действия выполнятся, если х равно 1
    break;
  case 2:
    // эти действия выполнятся, если х равно 2
    break;
  default:
    // Эти действия выполнятся, если x не равен ни одному из предыдущих значений case
  }

6 Циклы

6.1 Цикл while

Цикл выполняется, пока условие в скобках истинно:

x = 0;

while ( x < 5 )
{
    // это действие будет выполняться, пока х меньше 5
    x++;  // при каждом выполнении цикла увеличиваем х на 1
}

6.2 Цикл do while

Цикл похож на while, но, в отличии от него, цикл в любом случае выполнится хотя бы один раз (или больше, если при последующих проверках условие будет истинно):

x = 10;

do
{
   // это действие выполнится один раз, так как условие изначально ложно
}
while ( x < 5 );

6.3 Цикл for

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

for ( int x = 0; x < 5; x ++ )
{
    // при каждом выполнении этих действий переменная х будет увеличивать на 1
    // действия будут выполняться пока х меньше 5
}

7 Функции

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

Любой код в операции «Скрипт С++» должен находиться в функции. При использовании нескольких функций в скрипте будет выполняться только первая, остальные должны быть вызваны из нее:

void main ()
{
  int x = 1;
  function ();  // вызов функции, программа переходит в void function()
  SetNodeValueAsInt(“/Конфигурация/Станция/Сигналы/Constant2”, x);
}

void function ()
{
  SetNodeValueAsInt(“/Конфигурация/Станция/Сигналы/Constant2”, 5);
  // теперь программа возвращается обратно в void main()
}

После выполнения данного скрипта значение сигнала Constant1 станет равно 5, а Constant2 равно 1.

Если переменная была объявлена в функции, то она не будет доступна за ее пределами.

7.1 Функции с параметрами

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

Рисунок 72 – Передача параметров в скрипт в задаче ПЛК

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

void summ (int x, int y)  // в функцию передаются параметры х = 1 и y = 2
{
  int z = x + y;  // z равно 3
}

7.2 Возврат значения

Для передачи значения из скрипта можно указать необходимое значение в действии return, указав тип функции такой же, как у возвращаемого значения:

bool R_Output ( bool x, bool y )
{
  bool z = false;
  z = x && y;

  return z; // z передается на выход скрипта
}

На Рисунок 73 выход out4 привязан к выходу субмодуля R. После выполнения скрипта выход 1 субмодуля будет замкнут.

Рисунок 73 – Получение значения из скрипта в задаче ПЛК

8 Специализированные функции среды разработки

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

8.1 Функции для работы с узлами

Определение функции Описание
float GetNodeValueAsFloat(string strNodePath) Получить значение узла в виде float по заданному пути
void SetNodeValueAsFloat(string strNodePath, float fValue) Установить значение узла в float по заданному пути
int GetNodeValueAsInt(string strNodePath) Получить значение узла в виде int по заданному пути
void SetNodeValueAsInt(string strNodePath, int iValue) Установить значение узла в int по заданному пути
string GetNodeValueAsString(string strNodePath) Получить значение узла в виде string по заданному пути
void SetNodeValueAsString(string strNodePath, string strValue) Установить значение узла в виде string по заданному пути
bool GetNodeValueAsBool(string strNodePath) Получить значение узла в виде bool по заданному пути
void SetNodeValueAsBool(string strNodePath, bool bValue) Установить значение узла в виде bool по заданному пути
bool NodeValueIsError(string strNodePath) Проверка значения узла на ошибку
void StartNode(string strNodePath) Запуск узла по заданному пути
void StopNode(string strNodePath) Остановка узла по заданному пути

8.2 Функции для работы с окнами

Определение функции Описание
CloseWindow(string strNodePath, int iDisplay) Закрыть окно по заданному пути на выбранном дисплее
ShowWindow(string strNodePath, int iDisplay) Отобразить окно по заданному пути на выбранном дисплее

8.3 Функции для работы с временем

Определение функции Описание
int GetCurrentTime() Получение текущего времени в UNIX формате (количество секунд с 01 января 1970 года)
int GetLocalTime() Получение текущего времени в UNIX формате (количество секунд с 01 января 1970 года) с учетом часового пояса.
int GetHours(int iTime) Получение текущего часа из времени в формате UNIX
int GetMinutes(int iTime) Получение текущих минут из времени в формате UNIX
int GetSeconds(int iTime) Получение текущих секунд из времени в формате UNIX

9 Пример использования скрипта для решения задачи

Приведенный ниже пример демонстрирует один из вариантов решения реальной практической задачи. Для реализации необходимого алгоритма работы задействованы узлы, взаимодействующие с входами / выходами контроллера или хранящие значения, и скрипт С++. Связи между узлами и скриптом заданы в задаче ПЛК (см. Рисунок 74).

На вход скрипта подаются значения некоего сигнала (Signal) и уставки (Constant). В том случае, если сигнал больше уставки, замыкается релейный выход (out0). Соотношение между сигналом и уставкой переводится в проценты и записывается в переменную Percent. Если это соотношение становится меньше определенного значения, то соответствующее сообщение записывается в переменную Alert.

Рисунок 74 – Графическое представление задачи ПЛК для примера

Текст скрипта:


bool main (float signal_val, float constant_val)  // функция получает значения сигнала и уставки {   float ratio;             // переменная, в которой будет храниться соотношение сигнала и уставки   ratio = signal_val / constant_val; // вычисление соотношения
  percent_write(ratio);             // вызов функции записи в узлы, с передачей в нее соотношения
  if ( signal_val > constant_val)   {    return true;                   // если сигнал больше уставки, на выход скрипта приходит true   }   else   {    return false;               // если сигнал не больше уставки, на выход скрипта приходит false   } }
void percent_write (double ratio) // функция записи в узлы {   string message = "Значение в пределах нормы"; // текстовое сообщение по умолчанию   double percent = ratio * 100;                // вычисляется процентное соотношение   if ( percent < 50 )   {    message = "Значение ниже нормы!";           // если процентное соотношение меньше 50                                              // то текст сообщения меняется                                           }   // запись текстового сообщения в нужный узел   SetNodeValueAsString("/Конфигурация/Станция/Сигналы/Alert", message);   // запись процентного соотношения в нужный узел                                               SetNodeValueAsFloat("/Конфигурация/Станция/Сигналы/Percent", percent);                                               }

10 Приоритет операций

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

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

Символ Операция
:: Оператор разрешения области видимости
[] Оператор индексации
++ -- Постинкремент и декремент
. Доступ
++ -- Преинкремент и декремент
! Логическое НЕ
+ - Унарный положительный и отрицательный
~ Побитовое дополнение
@ Ссылка

Эта таблица показывает приоритет бинарных и тернарных операторов в порядке убывания.

Символ Операция
** Экспонента
* / % Умножить, разделить, по модулю
+ - Сложить и вычесть
<< >> >>> Сдвиг влево, сдвиг вправо и арифметический сдвиг вправо
& Побитовое И
^ Побитовый XOR
| Побитовое ИЛИ
<= < >= > Сравнение
== != is !is xor ^^ Равенство, идентичность и логическое исключающее ИЛИ
and && Логическое И
or || Логическое ИЛИ
?: Условие
= += -= *= /= %= **= &=

|= ^= <<= >>= >>>=

Присваивание и составные присваивания

11 Зарезервированные ключевые слова

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

and

abstract

auto

bool

break

case

cast

catch

class

const

continue

default

do

double

else

enum

explicit

external

false

final

float

for

from

funcdef

function

get

if

import

in

inout

int

interface

int8

int16

int32

int64

is

mixin

namespace

not

null

or

out

override

private

property

protected

return

set

shared

super

switch

this

true

try

typedef

uint

uint8

uint16

uint32

uint64

void

while

xor