PDA

Просмотр полной версии : [Урок] Мифы о Pawn-скриптинге - #8



Daniel_Cortez
22.02.2016, 21:01
Внимание: данная тема закрыта для защиты от копирования.
Если есть какие-то вопросы, замечания или просто пожелания по поводу данного урока - оставляйте их здесь (http://pro-pawn.ru/showthread.php?12774-%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5).




Миф 8: "Если переменная принимает только значения 0/1 или true/false, лучше объявить её как bool, чтобы сэкономить память."

Статус: Опровергнут.

Описание:

Этот миф, как и многие другие, изначально форсили на govno-info (и, судя по их целевой аудитории, миф этот оттуда никогда не исчезнет).
Соль лишь в том, что Pawn сильно отличается от других Си-подобных языков и в нём нельзя задать размер переменной, отличный от 4 байт.


Доказательство:
В Pawn размер данных обычно измеряется не в байтах, а в ячейках. В версии для SA:MP ячейка занимает 4 байта, но в других версиях её размер может быть равен 2 или 8 байтам.
Типов данных, как таковых, в Pawn тоже нет (сам по себе интерпретатор умеет оперировать только целыми числами, а для вещественных введены нативные функции). Вместо них есть теги, которые были сделаны, чтобы было проще избежать ошибок при написании кода.
Каждая переменная в Pawn занимает 4 байта (1 ячейку), независимо от её тега, поэтому если объявить переменную с тегом bool, её размер всё равно будет 4 байта.

Докажем это на примере записи статуса авторизации у игроков.
Сделаем два образца: в одном объявим массив без указания тега и будем записывать в него 1/0, а в другом укажем тег bool и будем записывать true/false.

Образец 1:

#include <a_samp>

new player_login_status[MAX_PLAYERS] = {0, ...};

public OnPlayerConnect(playerid)
{
player_login_status[playerid] = 1;
}

public OnPlayerDisconnect(playerid, reason)
{
player_login_status[playerid] = 0;
}


Образец 2:

#include <a_samp>

new bool:player_login_status[MAX_PLAYERS] = {false, ...};

public OnPlayerConnect(playerid)
{
player_login_status[playerid] = true;
}

public OnPlayerDisconnect(playerid, reason)
{
player_login_status[playerid] = false;
}


Скомпилируем оба образца с ключами "-d0 -O1 -v2".
Образец 1:


Header size: 140 bytes
Code size: 92 bytes
Data size: 4000 bytes
Stack/heap size: 16384 bytes; estimated max. usage=9 cells (36 bytes)
Total requirements: 20616 bytes

Образец 2:


Header size: 140 bytes
Code size: 92 bytes
Data size: 4000 bytes
Stack/heap size: 16384 bytes; estimated max. usage=9 cells (36 bytes)
Total requirements: 20616 bytes

Никаких различий. Тогда сравним ассемблерные листинги:

Образец 1:


CODE 0 ; 0
;program exit point
halt 0


DATA 0 ; 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0

CODE 0 ; 8
proc ; OnPlayerConnect
; line 6
;$lcl playerid c
; line 7
zero.alt
load.s.pri c
idxaddr
move.alt
const.pri 1
stor.i
;$exp
zero.pri
retn

proc ; OnPlayerDisconnect
; line b
;$lcl reason 10
;$lcl playerid c
; line c
zero.alt
load.s.pri c
idxaddr
move.alt
zero.pri
stor.i
;$exp
zero.pri
retn


STKSIZE 1000

Образец 2:


CODE 0 ; 0
;program exit point
halt 0


DATA 0 ; 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump 0 0 0 0 0 0 0 0

CODE 0 ; 8
proc ; OnPlayerConnect
; line 6
;$lcl playerid c
; line 7
zero.alt
load.s.pri c
idxaddr
move.alt
const.pri 1
stor.i
;$exp
zero.pri
retn

proc ; OnPlayerDisconnect
; line b
;$lcl reason 10
;$lcl playerid c
; line c
zero.alt
load.s.pri c
idxaddr
move.alt
zero.pri
stor.i
;$exp
zero.pri
retn


STKSIZE 1000


Содержимое листингов тоже совпадает, а значит что объявление переменных с тегом bool для записи true/false вместо 1/0 абсолютно никак не влияет на генерируемый код и не приводит к экономии памяти. Что и требовалось доказать.

Тем не менее, можно сэкономить место в секции данных, если задать размер массива, используя оператор char.
Этот оператор работает следующим образом: X char = (X+3)/4.
Здесь 4 - кол-во байт в ячейке. Прибавление 3 сделано потому, что если просто разделить число на 4, то результат может оказаться неправильным. Например, для 6 char нельзя выделить полторы ячейки, нужно две.
Для доступа к байтам вместо ячеек нужно использовать фигурные скобки вместо квадратных.

#include <a_samp>

new player_login_status[MAX_PLAYERS char] = {0, ...};

public OnPlayerConnect(playerid)
{
player_login_status{playerid} = 1;
}

public OnPlayerDisconnect(playerid, reason)
{
player_login_status{playerid} = 0;
}

Отчёт о компилцяии:


Header size: 140 bytes
Code size: 116 bytes
Data size: 1000 bytes
Stack/heap size: 16384 bytes; estimated max. usage=9 cells (36 bytes)
Total requirements: 17640 bytes

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


Вывод: в Pawn нет типов данных, есть только теги, и если объявить переменную с тегом bool, она всё так же будет занимать 4 байта (1 ячейку).



Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Не разрешается копирование данной статьи на других ресурсах без разрешения автора.