PDA

Просмотр полной версии : [Урок] Использование #pragma



makarov
03.05.2015, 19:48
Использование #pragma

Всем привет, сегодня я научу вас как правильно использовать #pragma, многие думают что данная директива устраняет ошибки и предупреждения компилятора, но на самом деле это не так.

Что такое #pragma

На самом деле #pragma используется для изменения настроек компилятора, эта директива не как не устраняет ошибки или предупреждения отправляемые компилятором.

Я часто замечаю советы людей использовать #pragma, для устранения предупреждений или ошибок, посылаемые компилятором.
С помощью директивы #pragma вы можете только скрыть некоторые предупреждения и ошибки, на самом деле проблемы останутся в вашем коде, и не исчезнут волшебным способом.

В своем уроке я расскажу все что знаю о #pragma и как избежать её использовать.

#pragma dynamic

Самая популярная из всех существующих.


#pragma dynamic 1000000

Динамически устанавливает параметр размера стека.
Иногда вы можете получить при компилировании своего скрипта такое уведомление:



Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase

Header size: 19036 bytes
Code size: 1327124 bytes
Data size: 43915204 bytes
Stack/heap size: 16384 bytes; estimated max. usage: unknown, due to recursion
Total requirements:45277748 bytes


Это предупреждение связано с редкими массивами, ненужных размеров и строк с использованием большого объема данных.

Например вы выделяете под стринговую область 2000 ячеек, а вам нужно всего 256:

Пример не правильного использования области памяти.


new string[2024];
format(string,sizeof(string),"%s, игрок зашел на сервер. По-приветствуем игрока.", GetPlayerNameEx(playerid));


Пример правильно использования.


new string[50+MAX_PLAYER_NAME+1];
format(string,sizeof(string),"%s, игрок зашел на сервер. По-приветствуем игрока.", GetPlayerNameEx(playerid));


Так же рассмотрим пример с большим не нужным выделением слотов в массиве.

Пример не правильного использования


#define MAX_CARS 1000
#define MAX_CAR_ITEMS 100
new CarItem[MAX_CARS][MAX_CAR_ITEMS][CAR_ITEM_DATA];


Спросите себя: Действительно ли вы должны использовать все это пространство?

Этот массив примерно 400 килобайт, не включая данные счетчиков.
Это очень много по сравнению с сегодняшним меркам, конечно все это можно сократить в 10 или даже 50 раз.

Пример правильно использования.


#define MAX_CARS 1000
new CarItem[MAX_CARS * 40][CAR_ITEM_DATA];


Размер этого массива теперь 40 килобайт, в отличие от 400 килобайт другого массива.

1 ячейка - 4 байта.

#pragma tabsize

Так же самая популярная директива среди рлсбыдлокдеров

Она отвечает за размер табуляции в вашем скрипте, который устанавливается по умолчанию до 4.
Если вы устанавливаете этот параметр до нуля в основном вы можете писать не читаемый код.

Вы вообще не должны изменять размер табуляции, установленный по умолчанию.
Чтобы избежать ошибок связанных с табуляцией вам нужно научиться делать правильно отступы в вашем коде.

Пример плохой табуляции


Dialog:ElectricRadio(playerid, response, listitem, inputtext[])
{
if (response)
{
new vehicleid = GetPlayerVehicleID(playerid);

if (GetPlayerState(playerid) != PLAYER_STATE_DRIVER || !IsEngineVehicle(vehicleid))
return 0;

switch (listitem)
{
case 0: SetVehicleRadio(vehicleid, "http://72.13.83.151/");
case 1: SetVehicleRadio(vehicleid, "http://173.192.207.51:8062/");
case 2: SetVehicleRadio(vehicleid, "http://212.83.60.202:8000/");
}
}
return 1;
}


Пример правильной табуляции


Dialog:ElectricRadio(playerid, response, listitem, inputtext[])
{
if (response)
{
new vehicleid = GetPlayerVehicleID(playerid);

if (GetPlayerState(playerid) != PLAYER_STATE_DRIVER || !IsEngineVehicle(vehicleid))
return 0;

switch (listitem)
{
case 0:
SetVehicleRadio(vehicleid, "http://72.13.83.151/");

case 1:
SetVehicleRadio(vehicleid, "http://173.192.207.51:8062/");

case 2:
SetVehicleRadio(vehicleid, "http://212.83.60.202:8000/");
}
}
return 1;
}


Вывод

Не используйте #pragma для исправления предупреждений и ошибок компилятора.

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

Автор: makarov (Некоторые материалы были взяты у Emmet_).

Desulaid
03.05.2015, 20:04
#pragma - функция? Я всегда считал ее директивой.

makarov
03.05.2015, 20:09
#pragma - функция? Я всегда считал ее директивой.

Спасибо за поправку.

Desulaid
03.05.2015, 20:15
Вот лично мне бы хотелось услышать об #pragma rational

#pragma rational Float /* floating point format */
#pragma rational Fixed(3) /* fixed point, with 3 decimals */

Я про них вычитал в оф. документации, пытался понять, но ничего не понял.

Оф. документация, стр. 89

makarov
05.05.2015, 15:39
Вот лично мне бы хотелось услышать об #pragma rational

#pragma rational Float /* floating point format */
#pragma rational Fixed(3) /* fixed point, with 3 decimals */

Я про них вычитал в оф. документации, пытался понять, но ничего не понял.

Оф. документация, стр. 89

Это не для этой темы и вообще не рекомендуется, для новичков и даже опытных, изменять этот параметр, он по умолчанию задан во float.inc.

// Тутор обновлен были неточности

Paradox
08.06.2015, 22:43
ну не скажи, если говорить конкретно про #pragma и не уточняя какую, то вот эта все же #pragma tabsize исправляет предупреждения табуляции.

#Vito
15.06.2015, 23:25
ну не скажи, если говорить конкретно про #pragma и не уточняя какую, то вот эта все же #pragma tabsize исправляет предупреждения табуляции.
Она их не исправляет, а просто скрывает.

Niko_Grey
16.06.2015, 06:42
Она их не исправляет, а просто скрывает.

Она устанавливает размер табуляции, вроде..

NewGreen
16.06.2015, 12:07
По большей части, подобные мануалы просто вводят в заблуждение, читайте книги

1. #pragma dynamic



Stack/heap size: 16384 bytes; estimated max. usage: unknown, due to recursion


Это предупреждение связано не только с лишними массивами и т.п., по большей части выводится из за рекурсии типа:



stock helloRecursion(num)
{
helloRecursion(num - 1);
}


2. С чего вы взяли что массив стал меньше ?
если за место выражения MAX_CARS * 40 поставить результат этого выражения получится CarItem[40000][100] что равно 16 миллионов байт! Скомпилируйте этот код и взгляните на строку уведомления Data size: чтобы убедится.


#define MAX_CARS 1000
new CarItem[MAX_CARS * 40][CAR_ITEM_DATA];


Лучше вместо этого изменить размер константы MAX_CARS установив меньшее значение.
Подсчитать занимаемый размер двумерного массива можно так:

array[x][y] => x * y * 4 = array[MAX_CARS][CAR_ITEM_DATA] = (1000 * 100) * 4 = 100000 * 4 = 400000 байт = 390 КБайт

array[x][y] => x * y * 4 = array[MAX_CARS * 40][CAR_ITEM_DATA] = (40000 * 100) * 4 = 4000000 * 4 = 16000000 байт = 15625 КБайт = 15 МБайт.

15 Мегабайт - это память занимаемая вашей переменной!

Daniel_Cortez
16.06.2015, 12:35
2. Зачем заставлять сервер каждый раз, при объявлении переменной, определять её размер через сложение заранее известных константных значений ?

new string[50+MAX_PLAYER_NAME+1];
рациональнее сразу сложить и задать нужный размер:

new string[75];
А теперь докажите, что вычислением константных выражений занимается сервер, а не компилятор.

NewGreen
16.06.2015, 13:45
А теперь докажите, что вычислением константных выражений занимается сервер, а не компилятор.

Не стану доказывать, константные выражения обрабатываются во время компиляции, тем не менее,
нет смысла, писать подобные выражения, используя нативные константы, размер которых вряд ли будет изменен, это лишняя пустая трата времени на печать лишних символов.


new string[50+MAX_PLAYER_NAME+1];

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

Обновил первый пост.

$continue$
16.06.2015, 13:48
Не стану доказывать, константные выражения обрабатываются во время компиляции, тем не менее,
нет смысла, писать подобные выражения, используя нативные константы, размер которых вряд ли будет изменен, это лишняя пустая трата времени на печать лишних символов.


new string[50+MAX_PLAYER_NAME+1];

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

Обновил первый пост.

Дело утопающего - дело рук самого утопающего.
В приципе, примера с изменением MAX_PLAYERS в 0.3.7z тебе будет достаточно?
Что, куй не предсказуем :crazy:

NewGreen
16.06.2015, 13:54
В приципе, примера с изменением MAX_PLAYERS в 0.3.7z тебе будет достаточно?

Не знал что изменять значение MAX_PLAYERS возможно только 0.3.7z, и что за версия такая 0.3.7z, новый релиз ?

$continue$
16.06.2015, 16:37
Не знал что изменять значение MAX_PLAYERS возможно только 0.3.7z, и что за версия такая 0.3.7z, новый релиз ?


Лол, я про константу.

NewGreen
16.06.2015, 16:56
Лол, я про константу.

А я про ежа, нужно внимательнее читать.

$continue$
16.06.2015, 17:07
А я про ежа, нужно внимательнее читать.

facepalm

ТЫК (http://wiki.sa-mp.com/wiki/GetPlayerPoolSize)

Я не про дириктивы вида:


#undef MAX_PLAYERS
#define MAX_PLAYERS 100

И читать Вам внимательней надо, я говорю про Куя, вы мне про скриптово -_-

NewGreen
16.06.2015, 17:25
facepalm

ТЫК (http://wiki.sa-mp.com/wiki/GetPlayerPoolSize)

Я не про дириктивы вида:


#undef MAX_PLAYERS
#define MAX_PLAYERS 100

И читать Вам внимательней надо, я говорю про Куя, вы мне про скриптово -_-

Она возвращает наивысший ID игрока но, для чего, Вы, привели эту функцию в качестве примера ? на сколько мне известно, она в основном предназначена для циклов, т.к. с версии 0.3.7 константа MAX_PLAYERS имеет значение 1000 по умолчанию.

Суть написанного мной до этого, заключалась в том что быстрее написать:


new string[75];

чем расписывать тоже самое в виде арифметического выражения:


new string[50+MAX_PLAYER_NAME+1];

p.s. кто такой или что такое Куй ? (надеюсь что это не завуалированная форма нехорошего слова :grin:)

Daniel_Cortez
16.06.2015, 17:35
Суть написанного мной до этого, заключалась в том что быстрее написать:


new string[75];

чем расписывать тоже самое в виде арифметического выражения:


new string[50+MAX_PLAYER_NAME+1];


Не осилили клавиатуру и печатаете со скорость 2-3 символа в секунду?
Ибо не вижу другой причины отказываться от понятных человеку формул в пользу "магических" чисел. Под "человеком" я имею в виду любого нормального скриптера, кто не знаком с вашим кодом и знает хоть какие-то основы английского языка (ибо не нужно подстраиваться под быдлокодеров, пусть сами учатся и не заставляют из-за себя портить чужой код).

Серьёзно, в чём профит?
В OnPlayerKeyStateChange вы точно так же используете заученные наизусть числа вместо читабельных констант? (любимый приём не осиливших основы инглиша)

И да, оставлю напоследок:

https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29#.D0.9F.D0.BB.D0.BE.D1.85.D0.B0.D1.8F_.D0.BF.D1.80.D0.B0.D0.BA.D1.82.D0.B8.D0.BA.D0.B0_.D0.BF.D1.80.D0.BE.D0.B3.D1.80.D0.B0.D0.BC.D0.BC.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D1.8F

Desulaid
16.06.2015, 18:16
Весь спор из-за использования арифметического выражения в массиве? :mosking:

NewGreen
16.06.2015, 22:16
Не осилили клавиатуру и печатаете со скорость 2-3 символа в секунду?
Ибо не вижу другой причины отказываться от понятных человеку формул в пользу "магических" чисел. Под "человеком" я имею в виду любого нормального скриптера, кто не знаком с вашим кодом и знает хоть какие-то основы английского языка (ибо не нужно подстраиваться под быдлокодеров, пусть сами учатся и не заставляют из-за себя портить чужой код).


Если Вам дадут один час, одну задачу (решение которой занимает около 500 строк кода), и условие писать код на скорость, соревнуясь с другими участниками, кто первый напишет (рабочее решение) тот и победитель, Вы по прежнему, будете объявлять все переменные в виде:


new string[50+MAX_PLAYER_NAME+1];

или выберите скорость ?



В OnPlayerKeyStateChange вы точно так же используете заученные наизусть числа вместо читабельных констант? (любимый приём не осиливших основы инглиша)


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

$continue$
16.06.2015, 22:53
Если Вам дадут один час, одну задачу (решение которой занимает около 500 строк кода), и условие писать код на скорость, соревнуясь с другими участниками, кто первый напишет (рабочее решение) тот и победитель, Вы по прежнему, будете объявлять все переменные в виде:


new string[50+MAX_PLAYER_NAME+1];

или выберите скорость ?



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

Прям много потратим на написания "MAX_PLAYER_NAME"?

_________________________________________________________________

Я б хотел посмотреть на ваше лицо, когда у Вас в моде 30к строк, у вас онлайн на сервере 400 (допустим), Вам нужно выпускать обновление но, вдруг Калкор меняет максимально допустимое значения ника - в итоге Вы будете сидеть массивы переписывать :)

NewGreen
16.06.2015, 23:10
Прям много потратим на написания "MAX_PLAYER_NAME"?
Попробуйте сначала 10 раз написать MAX_PLAYER_NAME
потом 10 раз его числовой эквивалент



Я б хотел посмотреть на ваше лицо, когда у Вас в моде 30к строк, у вас онлайн на сервере 400 (допустим), Вам нужно выпускать обновление но, вдруг Калкор меняет максимально допустимое значения ника - в итоге Вы будете сидеть массивы переписывать :)

И не поспоришь :-)

$continue$
16.06.2015, 23:14
Попробуйте сначала 10 раз написать MAX_PLAYER_NAME
потом 10 раз его числовой эквивалент


И не поспоришь :-)

Вот собственно спор и решен :)

Daniel_Cortez
17.06.2015, 05:52
Если Вам дадут один час, одну задачу (решение которой занимает около 500 строк кода), и условие писать код на скорость, соревнуясь с другими участниками, кто первый напишет (рабочее решение) тот и победитель, Вы по прежнему, будете объявлять все переменные в виде:


new string[50+MAX_PLAYER_NAME+1];

или выберите скорость ?
Это вообще отдельная тема и случаются такие ситуации сравнительно редко (речь конкретно про скриптинг на Pawn, здесь заказчик обычно готов дать немного больше времени, чтобы получить нормальный код, а не кучу говнокода). Поэтому чаще следует думать не о том, как бы побыстрее нажать на клавиши, а о том, как грамотнее сделать код, удобный для отладки и сопровождения в будущем.
Вы же преподносите всё так, как будто спешить нужно всегда. Не надо учить других быдлокодить.

Про стандартные константы SA:MP, надеюсь, вы уже поняли. Константы в a_samp.inc сделаны куем (Kye/Kalcor), а потому он же может изменить их в будущих версиях SA:MP, как пожелает. В SA:MP wiki тоже не написано никакой гарантии того, что константы не изменится в будущих версиях, а потому возможность всегда есть.