[SourcePawn] Урок 1 - Основы языка (Часть 2)

R1KO

всё тлен
Супермодератор
Сообщения
8,482
Реакции
5,940
[SourcePawn] Урок 1 - Основы языка (Часть 2)

<- К содержанию

  1. <- Часть 1
  2. Функции
    Функция - фрагмент программного кода (подпрограмма), выполняющий определенные действия, к которому можно обратиться из другого места программы. После выполнения функции управление возвращается обратно в точку программы, где данная функция была вызвана.
    Прототип функции - объявление функции, не содержащее тела функции, но указывающее имя функции, типы аргументов и возвращаемый тип данных. В то время как определение функции описывает, что именно делает функция, прототип функции может восприниматься как описание её интерфейса.
    Функция состоит из
    • Типа функции
      • native: Прототип внешней функции, которая создана другими плагинами или расширениями
        PHP:
        native bool IsValidClient(int iClient);
        /*
        Сообщаем компилятору что существует внешняя функция с возвращаемым типом данных bool, которой необходимо передать 1 аргумент типа int
        */
      • public: Внешняя функции, которая вызывается другими плагинами или расширениями
        PHP:
        public void OnMapStart()    // Внешняя функция OnMapStart вызывается ядром самого sourcemod`а
        {
            // код
        }
      • normal: Нормальная функция, которая может быть вызвана только внутри текущего плагина (при этом слово normal не пишется)
        PHP:
        void MyFunction()    // Внутренняя функция MyFunction
        {
            // код
        }
      • static: Тоже что и normal но функция доступна только в пределах текущего документа
      • stock: Тоже что и normal но если функция не вызывается нигде в плагине - компилятор не включает её в исполняемый файл (smx)
      • forward: Глобальное событие, вызываемое другими плагинами или расширениями. Является обратным вызовом и записывается только как прототип.
        PHP:
        forward void MyFunction();    // Сообщаем компилятору что существует внешняя функция MyFunction пустого типа без аргументов
    • Типа данных функции
      Аналогично типам данных переменных, но добавлен еще 1 тип:
      • void - Пустой тип. Означает что функция не возвращает никакого значения.
    • Имени функции
      К имени функции применяются те же требования что и к имени переменной
    • Параметров и аргументов функции
      Параметры функции - это значения, которые должна принимать функция.
      Аргументы функции - это те значения, которые передают в функцию при её вызове.
      PHP:
      public void OnMapStart()    // Функция без параметров
      {
          MyFunc(аргумент1, аргумент1);    // Вызов функции, передаем аргументы
      }
      
      int MyFunc(параметр1, параметр2)    // Объявляем функцию, принимаем параметры
      {
         // код
      }
      Параметры и аргументы у функции могут отсутствовать.
      PHP:
      public void OnMapStart()    // Функция без параметров
      {
          int a = 5;
          int b = AddNumbers(a, 9);    // Вызываем нашу функцию передавая её 2 аргумента
          // b сейчас равно 14
      }
      
      int AddNumbers(int param1, int param2)    // Объявляем функцию, которая имеет 2 параметра типа int. При этом называть их можно любым удобным именем.
      {
          // param1 сейчас равно 5
          // param2 сейчас равно 9
          
          int iResult = param1+ param2; // Прибавляем наши числа и записываем это в переменную iResult
          return iResult;    // Возвращаем значение iResult как значение функции
      }

    Синтаксис объявления функции:
    [Тип функции] <Тип данных функции> <Имя функции> ([параметр 1], [параметр 2], ...)

    Есть 2 способа вызова функции:
    • Прямой вызов - Вы специально вызываете функцию в вашем коде.
      PHP:
      public void OnMapStart()
      {
          MyFunction();    // Вызываем нашу функцию
      }
      
      void MyFunction()    // Объявляем функцию
      {
          // код
      }
    • Обратный вызов - В этом случае вы передаете в функцию1 имя другой функции (функцию2) и по завершению исполнения фукнции1 будет вызваная функция2
    PHP:
    public void OnMapStart()
    {
        MyFunction1(MyFunction2);    // Вызываем нашу функцию MyFunction1, передавая как аргумент функцию MyFunction2
    }
    
    void MyFunction1(Function MyFunctionCallBack)    // Объявляем функцию MyFunction1
    {
        // код
        Call_StartFunction(null, MyFunctionCallBack);        // Вызываем нашу функцию которую передали
        Call_Finish();
    }
    
    void MyFunction2()    // Объявляем функцию MyFunction2
    {
        // код
    }
    Возврат (return)
    Оператор return может быть 2-х видов
    Типы данных
    • return; - Просто завершает выполнение функции и передает управление в ту часть кода, откуда функция была вызвана.
    • return значение; - Завершает выполнение функции и передает управление в ту часть кода, откуда функция была вызвана, при этом возвращая значение как значение функции.
      PHP:
      public void OnMapStart()
      {
          int b;
          // b сейчас равно 0
          b = AddNumbers(3, 2);    // Вызываем нашу функцию
          // Функция примет значение 5 и оно будет присвоено переменной b
          // b сейчас равно 5
      }
      
      int AddNumbers(int arg1, int arg2)
      {
          int iResult = arg1 + arg2;
          return iResult;    // Возвращаем значение iResult как значение функции
          /*
          Либо можно записать так:
          return (arg1 + arg2);
          */
      }
      PHP:
      public void OnMapStart()
      {
          int a = 3;
          if(IsValidNumber(a))
          {
              // Код
          }
      }
      
      bool IsValidNumber(int iNum)
      {
          if(iNum > 0 && iNum < 10)    // Если число, которое передали в функцию больше 0 и меньше 10
          {
              return true;    // Вернем true
          }
          // Если условия выше выполнилось, то функция завершится и вернет true, а код ниже выполнен не будет
          return false;    // Вернем false
      }
    Для функций типа void return в конце функции не нужен, но может применяться return без значения для выхода из функции в нужный момент.

    Функции не могут возвращать массивы (строки тоже массивы).

    Значения по умолчанию
    В SourcePawn можно задать значение по умолчанию для любых параметров функции. Это значит, что если параметр не передан в функцию - он принимает значение по умолчанию.
    PHP:
    public void OnMapStart()
    {
        int a = 3,
            b = 6;
    
        int c = MyFunc(a, b, true);        // Прибавление
        int d = MyFunc(a, b, false);    // Вычитание
        int e = MyFunc(a, b);            // Прибавление
    }
    /*
    Функция MyFunc прибавляет или вычитает числа
    1-й параметр это число 1
    1-й параметр это число 2
    2-й параметр определяет действие:
        true - прибавляем
        false - вычитаем
    */
    int MyFunc(int iNum1, int iNum2, bool bAdd = true) // Если параметр bAdd не передан он будет принят как true
    {
        if(bAdd)    // Если bAdd равен true
        {
            return (iNum1 + iNum2);    // Вернем сумму
        }
        else    // Если bAdd не равен true значит он равен false, так что проверять это нет смысла.
        {
            return (iNum1 - iNum2);    // Вернем разность
        }
    
        return 0;
    }
    Когда пропускаемый параметр не последний заменяем его нижним подчеркиванием _
    PHP:
    public void OnMapStart()
    {
        int a = 3,
            b = 6;
    
        int c = MyFunc(a, true, b);        // Прибавление
        int d = MyFunc(a, false, b);    // Вычитание
        int e = MyFunc(a, _, b);            // Прибавление
    }
    
    int MyFunc(int iNum1, bool bAdd = true, int iNum2) // Если параметр bAdd не передан он будет принят как true
    {
        if(bAdd)    // Если bAdd равен true
        {
            return (iNum1 + iNum2);    // Вернем сумму
        }
        else    // Если bAdd не равен true значит он равен false, так что проверять это нет смысла.
        {
            return (iNum1 - iNum2);    // Вернем разность
        }
    
        return 0;
    }
    Передача по ссылке
    Во всех примерах представленных ранее параметры в функции передавались по значению.
    Как это работает:
    PHP:
    public void OnMapStart()
    {
        int a = 3,
            b = 6;
    
        int c = AddNumbers(a, b);    // Передаем значения переменных a и b
        /*
        При этом мы передаем не сами переменные, а то значение, которое в них находится.
        Это значит что мы передаем числа 3 и 6.
        */
    }
    
    int AddNumbers(int iNum1, int iNum2) // Здесь создаются новые локальные переменные и они принимают значения, которые им были переданы
    {
        // Здесь iNum1 это новая локальная переменная, которая равна 3, следовательно равна a но она не является переменной a.
        // Если здесь мы изменим её, например, так:
        //    iNum1 = 7;
        //    Она станет равна 7, но переменная a в функции OnMapStart по прежнему останется равна 3
        return (iNum1 + iNum2);
    }
    Часто возникает необходимость вернуть 2 значения. Это можно сделать передав функции параметры не по значению, а по ссылке.
    PHP:
    public void OnMapStart()
    {
        int a = 3,
            b = 6;
    
        int c;
        //     c == 0
        AddNumbers(a, b, c);    // Передаем значения переменных a и b и адрес переменной с
        //     c == 9
    }
    
    void AddNumbers(int iNum1, int iNum2, int &iResult) // & означает, что функция получает не значение переменной, а её адрес
    {
        // Здесь переменная iResult это та же переменная что и c в функции OnMapStart;
        // Если мы её изменим здесь, то изменится и переменная c
        iResult = iNum1 + iNum2;
    }
    Массивы всегда передаются по ссылке, но символ & не ставится.
    PHP:
    public void OnMapStart()
    {
        int iArray[4] = {4, 5, 8, 1};
    
        MyFunc(iArray, 4);
        MyFunc2(iArray);
    }
    
    void MyFunc(int[] iArray, int iSize)    // Такая запись используется, если функция не знает точного размера массива, поэтому часто её нужно передать еще и размер массива
    {
        // Код
    }
    
    void MyFunc2(int iArray[4])    // Такая запись используется, если функция всегда должна принимать массив указанного размера
    {
        // Код
    }
  3. Методы
    Метод - это функция, принадлежащая какому-то классу или объекту.
    Например, в SourcePawn есть стандартный класс Panel, который является дочерним от Handle.
    Класс Panel имеет специальные функции для работы с ним.
    Несколько их них:
    • Panel - Конструктор класса, создает объект класса Panel (Создает панель)
    • SetTitle - Добавляет заглавие в панель
    • DrawItem - Добавляет пункт в панель
    • DrawText - Добавляет текст в панель
    • Send - Отправляет панель игроку.
    Эти функции и есть его методами.
    Более подробно о конкретных классах и их методах будет изложено в следующих уроках.

  4. Константы
    Константы - переменные, которые нельзя изменить после инициализации.
    Константы бывают:
    • Литеральные - Значение, записанное непосредственно в коде
      PHP:
      public void OnMapStart()
      {
          int a = 3;
      
          int c = AddNumbers(a, 4);    // 4 это литеральная константа
      }
      
      int AddNumbers(int iNum1, int iNum2)
      {
          return (iNum1 + iNum2);
      }
      • Именованные - Присвоение имени значению и последующая замена при компиляции
        PHP:
        #define NUMBER    4
        
        public void OnMapStart()
        {
            int a = 3;
        
            int b = a + NUMBER;    // NUMBER будет заменено на 4
        }
      • Перечисления - Для использования целочисленных констант можно использовать перечисления, в котором целочисленному значению сопоставляется определенное имя. По умолчанию первой константе задается значение 0, а другим значение на 1 большее, чем предыдущая константа.
        PHP:
        enum
        {
            NONE = -1,    // Первое значение -1
            SELF,        // == 0
            TEAM,        // == 1
            ALL,        // == 2
        };
        
        public void OnMapStart()
        {
            int iMode = TEAM;    // Значение равно 1
        }
      • Константы переменных - Это тип переменных, значение которым присваивается на этапе инициализации и его больше нельзя изменить.
        PHP:
        static const int g_iGlobalVar = 7;    // Переменная g_iGlobalVar всегда будет равно 7 и её нельзя изменить
        // static нужен при создании глобальных констант т.к. этого требует синтаксис
        
        public void OnMapStart()
        {
            const int iLocalVar = 9;    // Переменная iLocalVar всегда будет равно 9 и её нельзя изменить
        }
        PHP:
        public void OnMapStart()
        {
            char sVar[] = "string";
            MyFunc(sVar);
        }
        
        void MyFunc(const char[] sString)    // Функция не знает, какой реальный размер переданной строки, но переменную нельзя изменить
        {
            // Код
        }
        
        void MyFunc2(int iArray[4])    // Такая запись используется, если функция всегда должна принимать массив указанного размера
        {
            // Код
        }

    • Циклы
      Циклы - инструменты, которые позволяют многоразово выполнять блок кода.
      Цикл состоит из условия выполнения и тела цикла.
      Итерация - единичное выполнение тела цикла.
      • Цикл for - Используется, когда известно точное количество итераций
        PHP:
        for (действие до начала цикла; условие продолжения цикла; действия в конце каждой итерации цикла)
        {
            // Тело цикла
        }
        Частный случай:
        PHP:
        for (счетчик = значение; счетчик < значение; шаг цикла)
        {
            // Тело цикла
        }
        PHP:
        for (int i = 0; i < 5; i++)    // Будет выполнятся до тех пор, пока i меньше 5
        {
            PrintToServer("i = %i;", i);
        }
        /*
        int i = 0; - Здесь мы создали счетчик (переменная, которая ведет подсчет итераций)
        i < 5; - Это условие, которое проверяет перед каждой итерацией (Условие продолжения)
        i++ - Это действие, которое выполняется после каждой итерации
        */
        Результат выполнения:
        i = 0;
        i = 1;
        i = 2;
        i = 3;
        i = 4;
        PHP:
        Вот реальный пример. Цикл по всем игрокам:
        for (int i = 1; i <= MaxClients; ++i)
        {
            // Начинаем с 1 т.к. индексы игроков могут быть от 1 до MaxClients (включительно, поэтому и <=), которое равно количеству слотов на сервере.
            // Сам сервер имеет индекс 0
            if(IsClientInGame(i)) // Проверяем на сервере ли игрок (т.е. занят ли этот индекс (слот) игроком)
            {
                // Эта проверка всегда должна идти первой
                // Тут мы точно знает что игрок на сервере и можем получать любую информацию о нем.
                // Например:
                if(IsPlayerAlive(i)) // Жив ли игрок
                {
                    //
                }
                
                if(GetClientTeam(i) == 2) // Игрок играет за террористов
                {
                    // Возможные команды игроков
                    // 0 - Игрок только вошел на сервер и еще не выбрал команду
                    // 1 - Команда наблюдателей
                    // 2 - Команда террористов
                    // 3 - Команда контр-террористов
                }
        
                if(IsFakeClient(i)) // Является ли игрок ботом
                {
                    //
                }
            }
        }
      • Цикл while - Когда мы не знаем, сколько итераций должен произвести цикл. Данный цикл будет выполняться, пока условие, является истиной.
        PHP:
        while (условие продолжения цикла)
        {
            // Тело цикла
        }
        PHP:
        int i = 5;
        while (i > 0)
        {
            PrintToServer("i = %i;", i);
            i--;
        }
        Результат выполнения:
        i = 5;
        i = 4;
        i = 3;
        i = 2;
        i = 1;
      • Цикл do while - То же что и while, но проверка условия выполняется уже после выполнения итерации. Это гарантирует хотя бы одно выполнение цикла.
        PHP:
        do
        {
            // Тело цикла
        } while (условие продолжения цикла)
        PHP:
        int i = 5;
        do
        {
            // Тело цикла
            PrintToServer("i = %i;", i);
            i--;
        } while (i > 0)
      Операторы для работы с циклами
      • break; - Прекращает выполнение цикла и возвращает управление в функцию.
      • return [значение]; - Прекращает выполнение цикла и выходит из функции.
      • continue; - Пропускает выполнение текущей итерации цикла.
    • Ключевые слова
      Ключевые слова - это слова, которые зарезервированы самим SourcePawn и их нельзя использовать, как имена переменных и фукнций.
      К ним относятся if, for, return и другие.
      Если вы попытаетесь использовать ключевые слова как имена переменных и функций то получите ошибку:
      error 173: 'слово' is a newly reserved keyword that may be used in the future; use a different name as an identifier
    • Инструкции компилятора
      Инструкции компилятора - это инструкции, которые нужны для компилятора. После компиляции их нет в исполняемом файле.
      Инструкции компилятора всегда начинаются с символа #
      • #include - Подключает указанный файл/библиотеку
        Использование:
        • #include <sourcemod> - Подключает библиотеку sourcemod из папки include, относительно расположения компилятора
        • #include "myfile.sp" - Подключает файл myfile.sp по пути относительно текущего файла
      • #tryinclude - То же что и #include но если файла не существует то ошибки не будет.
      • #define имя_макроса последовательность_символов - Создает макрос. В результате, если компилятор обнаружит в тексте программы имя_макроса, то он заменит его на последовательность_символов.
        Макрос заканчивается переносом строки. Для экранирования переносов строк в макросе используется символ \
      • #if условие - Выполняет проверку условия. Требуется закрывающая директива #endif. Возможно ветвление используя директивы #else и #elseif
      • #if defined имя_макроса - Проверяет объявлен ли макрос.
      • #error "Ошибка" - Выдает ошибку компиляции.
      • #pragma - Директива используется для доступа к специфическим расширениям компилятора.
        Использование:
        • #pragma semicolon 1 - Сообщает компилятору о том, что в конце каждого выражения должен стоять символ ;
        • #pragma newdecls required - Сообщает компилятору о том, что синтаксис плагина исключительно новый
        • #pragma deprecated - Устанавливает для переменной/функции статус устаревшей
        • #pragma dynamic количество_байт - Устанавливает динамичную память плагина
        • #pragma unused - Отключает предупреждение о то что переменная не используется
        • #pragma tabsize размер - Устанавливает значение TAB (0 - отключает)
  5. <- Часть 1
Жду критики, пожеланий, предложений, отзывов.
 
Последнее редактирование:

gibs

Фитиль народного волненья
Сообщения
700
Реакции
252
Ну ты путаешь понятия препроцессорных деректив и встроенных функций. sizeof() - это встроенная функция.
На счёт процедур я бы не согласился. Тут стоит делать отсылку к си. В языке нету понятия процедуры, тут всё является функциями.
По поводу методов. Это переопредение стандартных типов. Классов и структур в павне как таковых нету. Можно создавать структуру через enum, описывать последовательность типов и объявлять массив, но это не совсем структура, да и какой это нафиг класс, который может хранить лишь одно единственное свойство.
С приходом методмапов язык остается как и раньше процедурным. В нормальном ООП языке был бы просто класс, который наследуется от интерфейсов, в методах которого описывались бы действия, что и являлось бы плагином. В пример могу привести написание С++ плагинов. Тут же методмапы были введены не в качестве стремления к ООП, а скорее ради возможности сокращать записи.
Для новичков и школьников я дам просто совет: если вы решили заняться программированием, то поверьте, сорспавн - это язык, с которого точно не стоит начинать этого делать. Он не является самостоятельным языком.
 

R1KO

всё тлен
Супермодератор
Сообщения
8,482
Реакции
5,940
Ну ты путаешь понятия препроцессорных деректив и встроенных функций. sizeof() - это встроенная функция.
На счёт процедур я бы не согласился. Тут стоит делать отсылку к си. В языке нету понятия процедуры, тут всё является функциями.
исправил.
По поводу методов. Это переопредение стандартных типов. Классов и структур в павне как таковых нету.
С приходом методмапов язык остается как и раньше процедурным. В нормальном ООП языке был бы просто класс, который наследуется от интерфейсов, в методах которого описывались бы действия, что и являлось бы плагином. В пример могу привести написание С++ плагинов. Тут же методмапы были введены не в качестве стремления к ООП, а скорее ради возможности сокращать записи.
Для новичков и школьников я дам просто совет: если вы решили заняться программированием, то поверьте, сорспавн - это язык, с которого точно не стоит начинать этого делать. Он не является самостоятельным языком.
Соглашусь, и так ясно что методмап это не класс, я "обозвал" их классами новичкам было проще ориентироваться.
 

AlmazON

Не путать с самим yand3xmail
Сообщения
5,146
Реакции
2,524
& означает, что функция получет не значение переменной, а её адрес
Опечатка.
Итерация - единичное выполнение тела цикла называется.
Лишнее.
Цикл for - Используется, когда известно точное количество итераций
Если верить тому же декомпилятору, то он всегда преобразуется в простой while. Разве не так? Или, всё же есть разница и, в качестве оптимизации действительно всегда стоит использовать for, когда число итераций заведомо известно?
 

R1KO

всё тлен
Супермодератор
Сообщения
8,482
Реакции
5,940
@AlmazON, судя по всему он действительно преобразуется, но for удобен в использовании, да и какая разница если после компиляции всё ровно получим одно и то же, лучше же делать удобно.
Остальное исправил
 

gibs

Фитиль народного волненья
Сообщения
700
Реакции
252
Если верить тому же декомпилятору, то он всегда преобразуется в простой while. Разве не так? Или, всё же есть разница и, в качестве оптимизации действительно всегда стоит использовать for, когда число итераций заведомо известно?
Я тебе уже говорил, что у тебя довольно искривлённое понятие оптимизации. Цикл фор - это попросту удобный оператор цикла, который призван делать написание кода более компактно и читаемо за счёт своей удобной структуры, и который входит в структуру языка. Если ты задаешь вопрос какой цикл использовать для оптимизации, то это полный п*здец, извините за выражение.
 

AlmazON

Не путать с самим yand3xmail
Сообщения
5,146
Реакции
2,524
какой цикл использовать для оптимизации
Тогда ещё назло спрошу: что оптимальнее использовать, цикл while или do while, если содержимое одно и то же, по сути (первое выполнение возможно без проверок)? :mosking:
попросту удобный оператор цикла
Замечу, что нигде не сказано об этом, будто они действительно обособлены друг от друга, а выполняют ту же функцию. Думаю, это полезно будет знать всем.
 

gibs

Фитиль народного волненья
Сообщения
700
Реакции
252
@AlmazON, это зависит от компилятора и уровня оптимизации компилятором. Если брать сорсмод, то исходный код транслируется в байт код, потом через jit в машинный код. Все опткоды для jit можно посмотреть тут, но основная документация тут. На деле циклы вайл и фор практически идентичны, отличаются лишь удобностью записи. В байт коде это по прежнему проверка условия и джампы по адресам. Первое и третье поле в цикле фор является не обязательным, обязательно указывать только проверка условий, так что можно использовать фор в качестве вайла, при этом байт код будет одинаковый. Но в цикле вайл нельзя создавать переменные, которые будут видимы только для тела цикла.
А вот пример.
PHP:
public Action Cmd_Test(int args)
{
    for (int i = 0, j = 0; i < 3; i++)
    {
        j = j + 2;
    }
  
    int i = 0, j = 0;
    while(i < 3)
    {
        j = j + 2;
        i++;
    }
  
    return Plugin_Handled;
}
PHP:
0xba0: break                          
0xba4: break                          
0xba8: push.c 0x0                       ; 0
0xbb0: push.c 0x0                       ; 0
0xbb8: jump 0xbcc                       ; +0x14
0xbc0: break                          
0xbc4: inc.s 0xfffffffc                 ; i
0xbcc: load.s.pri 0xfffffffc            ; i
0xbd4: const.alt 0x3                    ; 3
0xbdc: jsgeq 0xc08                      ; +0x2c
0xbe4: break                          
0xbe8: load.s.pri 0xfffffff8            ; j
0xbf0: add.c 0x2                        ; 2
0xbf8: stor.s.pri 0xfffffff8            ; j
0xc00: jump 0xbc0                       ; -0x40
0xc08: stack 0x8                        ; 8
0xc10: break                          
0xc14: push.c 0x0                       ; 0
0xc1c: push.c 0x0                       ; 0
0xc24: break                          
0xc28: break                          
0xc2c: load.s.pri 0xfffffffc            ; i
0xc34: const.alt 0x3                    ; 3
0xc3c: jsgeq 0xc74                      ; +0x38
0xc44: break                          
0xc48: load.s.pri 0xfffffff8            ; j
0xc50: add.c 0x2                        ; 2
0xc58: stor.s.pri 0xfffffff8            ; j
0xc60: break                          
0xc64: inc.s 0xfffffffc                 ; i
0xc6c: jump 0xc28                       ; -0x44
0xc74: break                          
0xc78: const.pri 0x3                    ; 3
0xc80: stack 0x8                        ; 8
0xc88: retn
В обоих случаях один и тот же сценарий
Код:
0xc2c: load.s.pri 0xfffffffc            ; i
0xc34: const.alt 0x3                    ; 3
0xc3c: jsgeq 0xc74                      ; +0x38
Подгружается два значения, и если не совпадают условия, то прыжок по адресу.
ЗЫ: и нету никакого там превращения из фора в вайл. Просто декомпилятор так интерпретирует опткоды
 
Сообщения
878
Реакции
351
2. Функции
<<Параметры (аргументы) функции
[Add+] Лучше разделить и описать их принцип.
2. Функции


P.S.:

<<Возврат (return)
<<return значение; - Завершает выполнение функции и передает управление в ту часть кода, откуда функция была вызвана, при это возвращая значение как значение функции.

[Add+] При возращении "return (значение или выражение" - объявляется неявно (временная) переменная, и она присваивается к той переменной(iResult), которая вызвала эту функцию 'AddNumbers(5, 9)'.

int iResult = AddNumbers(5, 9);

Объявляется неявно (временная) переменная - её время заканчивается: после успешного присвоения к переменной (iResult).


Параметры функций

<<Параметры функции - это значения, которые должна принимать функция.
<<Аргументы функции - это те значения, которые передают в функцию при её вызове.

[Fix*] Параметры функции -> Формальные параметры - аргументы, при объявлении функции.

PHP:
int AddNumbers(int param1, int param2) // Определяем функцию, которая имеет формальные параметры - 2 аргумента типа int: param1(a), param2(9).
{
   // тело функции.
}
[Fix*] Аргументы функции -> Фактические параметры - аргументы, передаваемые в функцию,
(аргумент может быть выражение).

PHP:
int a = 5;
int b = AddNumbers(a, 9); // Вызываем нашу функцию, передавая фактические параметры - 2 аргумента типа int: a(param1) и 9(param2).

[Add+] Если формальные параметры (их аргументы, при объявлении функции) - не передаются явно по ссылке (оператор &), или он не является массивом,-
т.е. передаются по значению (по умолчанию), и неявно присваивает фактический параметр, значения формального.

Образно (без констант):
- По значению:
Фактический параметр (аргумент, его значение копируется в)-> Формальный параметр. При этом неявно объявляется локальная переменная, именем равным формального параметра.

- По ссылке:
Фактический параметр (аргумент, его &адрес передается в)-> Формальный параметр. Не объявляется локальная переменная, но и доступна изменению по имени формального параметра.

- Массив:
Фактический параметр ((аргумент, (неявный &) его адрес-на первый элемент массива) передается в)-> Формальный параметр. Не объявляется локальная переменная, но и доступна изменению по имени формального параметра.


Если нужно передать только переменную - без её изменения в функции, то можно использовать передачу по ссылке со спецификатором const от случайного изменения.
PHP:
public void OnPluginStart()
{
   int iRes5 = 5;
   int iRes10 = 10;
   int iResult = AddNumbers(iRes5, iRes10);
   PrintToServer("Text_OnPluginStart - iResult = %d", iResult); // Text_OnPluginStart - iResult = 15

   int iEq = iResult;

   // Если переменная iRes5 больше не требуется, можно присвоить ей новое значение
   // главное не запутаться в именах, и/или присвоить ей имя под двойное значение,
   // например iRes5_iEq, чтобы не объявлять, как выше iEq ->
   // -> iRes5_iEq = iResult
   iRes5 = iResult;

   PrintToServer("Text_OnPluginStart - iEq = %d, iRes5 = %d", iEq, iResult); // Text_OnPluginStart - iEq = 15, iRes5 = 15


   // Аналог (аргумент как выражение):
   PrintNoCreateiResult(); // Простой вызов функции без фактических параметров
}

void PrintNoCreateiResult() // Без формальных параметров, iRes5 и iRes10 не передаются
{
   // объявляем новые локальные переменные для этой функции,
   // т.к. по области видимости с прежней функцией они - неизвестны.
   int iRes8 = 8;
   int iRes13 = 13;

   // Аргумент может быть выражение, т.к. при возращении (return) объявляется неявное (временная) переменная.
   // Поэтому нет нужды объявлять iResult, если не потребуется дальше в функции,
   // собственно замысел - аргумент как выражение.
   PrintToServer("Text_PrintNoCreateiResult - AddNumbers(iRes8, iRes13) = %d", AddNumbers(iRes8, iRes13)); // Text_PrintNoCreateiResult - AddNumbers(iRes8, iRes13) = 21

   //дальше iResult не требуется.

   //P.S.: т.к. AddNumbers(iRes5, iRes10) не конец выражения (в данный момент), поэтому после - символ ";" не ставиться.
}

int AddNumbers(const int &param1, const int &param2) // Определяем функцию, которая имеет формальные параметры - 2 аргумента типа int переданный их адрес: &param1(iRes5), &param2(iRes10).
{
   // При этом имеем в формальных параметрах (только переданный адрес), без неявного объявления локальных переменных.
   PrintToServer("Text_AddNumbers - param1 = %d, param2 = %d", param1, param2); // Text_AddNumbers - param1 = 5, param2 = 10
   return param1 + param2;
}

Text_AddNumbers - param1 = 5, param2 = 10
Text_OnPluginStart - iResult = 15
Text_OnPluginStart - iEq = 15, iRes5 = 15
Text_PrintNoCreateiResult - AddNumbers(iRes8, iRes13) = 21
 
Последнее редактирование:

R1KO

всё тлен
Супермодератор
Сообщения
8,482
Реакции
5,940
@DarklSide, мне кажется формальные и фактические только запутают, да и учить это лучше на других языках.
 

inklesspen

Юзя есть Юзя с его ключами :3
Сообщения
1,522
Реакции
500
Слишком много муккулатуры, долго читать...
Надо бы какой-нить краткий урок) Ото приходят со школы и лень уже (Живой пример - Я), и будут богаты таким знанием лишь те, кто уже отучились.
 
Сообщения
235
Реакции
9
Вопрос по циклу. Почему цикл только проверяет реальных игроков? И можно ли проверять реальных игроков с ботами?
 
Сообщения
235
Реакции
9
Как его сделаешь, так он и будет работать.
PHP:
for(int i = 1; i <= MaxClients; i++)    if(IsClientInGame(i))
{
    ...
}
Неа:
PHP:
for(new i=1; i<MaxClients; i++)
    {
        if (i != client && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i))
        {
            new Float:pos[3];
            GetClientAbsOrigin(i, pos);
            TeleportEntity(client, pos, NULL_VECTOR,NULL_VECTOR);
            //PrintToChatAll("tele %N to %N", client, i)
            break;
        }
    }
Если я один на сервере не считая ботов, телепортирует всегда камне.
 

Someone

Нужно больше модульности..
Сообщения
1,713
Реакции
1,048
Если я один на сервере не считая ботов, телепортирует всегда камне.
Как его сделаешь, так он и будет работать.
Ты тупо к себе телепортируешь живого террориста и после этого сразу цикл убиваешь break'ом.
 

Grey83

похухоль
Сообщения
2,884
Реакции
1,600
Если я один на сервере не считая ботов, телепортирует всегда камне.
потому что у первого зашедшего игрока обычно самый маленький индекс, а боты заходят после входа первого игрока и выходят после последнего
 

сапсан

Все держаться на костылях!
Сообщения
564
Реакции
323
@AlmazON, For это цикл с начальной и конечной переменной и с правилами ее изменения плюс переменная имеет только числовое значение
While - это цикл с условиями и будет работать пока условие верное
так что не знаю это две разные вещи и тут уж я не знаю как можно for преобразовать в while
--- Добавлено позже ---
Тогда ещё назло спрошу: что оптимальнее использовать, цикл while или do while, если содержимое одно и то же, по сути (первое выполнение возможно без проверок)?
do while сначала выполняется тело цикла, а затем проверяется условие продолжения
 
Последнее редактирование:
Сообщения
235
Реакции
9
потому что у первого зашедшего игрока обычно самый маленький индекс, а боты заходят после входа первого игрока и выходят после последнего
потому что у первого зашедшего игрока обычно самый маленький индекс, а боты заходят после входа первого игрока и выходят после последнего
Можешь показать как, без break не вариант, сообщений тогда много будет спамится.
PHP:
public Action TankCheckStuck(Handle timer, any client)
{
    if(client && IsValidEntity(client) && IsValidEdict(client) && IsClientInGame(client) && GetEntProp(client, Prop_Data, "m_StuckLast") >= 1)
    {
        PrintToChatAll("\x04Персонаж \x05%N \x04Застрял!!!", client);
        for (int i = 1; i <= MaxClients; i++)
            if (i != client && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i))
            {
                float pos[3];
                GetClientAbsOrigin(i, pos);
                TeleportEntity(client, pos, NULL_VECTOR,NULL_VECTOR);
                PrintToChatAll("\x04Персонаж \x05%N \x04Телепортирован к Персонажу \x05%N", client, i);
                break;
            }
    }
    if(iDTank == 0)
    {
        return Plugin_Stop;
    }
    return Plugin_Continue;
}
 

Grey83

похухоль
Сообщения
2,884
Реакции
1,600
@сапсан, сомневаюсь, что AlmazON прочитает твой коммент и тем более ответит на него: он давно не заходил на форум из-под своей учётки
Последняя активность AlmazON: 7 апр 2017
--- Добавлено позже ---
я не знаю как можно for преобразовать в while
А вот декомпилер знает :mocking:
Он превращает это:
PHP:
    for(int i = 1; i <= MaxClients; i++)
    {
        ...
    }
в это:
PHP:
	int i = 1;
	while (i <= MaxClients)
	{
		...
		i++;
	}
--- Добавлено позже ---
@alexmy, а тебе кого к кому нужно телепортировать?
 
Последнее редактирование:
Сверху