Pular para o conteúdo principal

Palavras-chave: diretivas

Diretivas são instruções passadas ao compilador para controlar como ele interpreta o código-fonte.

#assert

Verifica se uma expressão constante é verdadeira; caso contrário interrompe a compilação.

#define MOO 10
#assert MOO > 5

Compila normalmente.

#define MOO 1
#assert MOO > 5

Provoca um erro fatal. É semelhante a:

#define MOO 1
#if MOO <= 5
#error MOO check failed
#endif

A diferença é que #assert mostra a mensagem:

Assertation failed: 1 > 5

enquanto o segundo exibe:

User error: Moo check failed

#define

#define substitui texto: onde o símbolo declarado aparece, ele é trocado pelo conteúdo definido.

#define MOO 7
printf("%d", MOO);

Vira:

printf("%d", 7);

Por isso #defines não existem no código compilado; o pré-processador resolve tudo antes. Eles não precisam conter números:

#define PL new i = 0; i < MAX_PLAYERS; i++) if (IsPlayerConnected(i)

for (PL) printf("%d connected", i);

O código acima gera o clássico player loop. Note como parte dos parênteses vem do for e parte do macro.

Pouca gente sabe que você pode criar definições multilinha escapando a quebra de linha:

#define PL \
new i = 0; i < MAX_PLAYERS; i++) \
if (IsPlayerConnected(i)

Macros também podem receber parâmetros:

#define MOO(%0) \
((%0) * 7)

printf("%d", MOO(6)); // imprime 42
printf("%d", MOO(5 + 6)); // imprime 77

Os parênteses extras são importantes. Sem eles MOO(5 + 6) se expandiria para 5 + 6 * 7, que resulta em 47 devido à ordem das operações.

Se o número de argumentos fornecido for maior que o declarado, o último parâmetro recebe todos os valores restantes:

#define PP(%0,%1) \
printf(%0, %1)

PP(%s %s %s, "hi", "hello", "hi"); // imprime "hi hello hi"

O operador # transforma um literal em string; esse recurso é específico do SA-MP.

#else

Equivalente a else, mas usado em blocos condicionais do pré-processador (#if).

#elseif

Versão de else if para #if:

#define MOO 10

#if MOO == 9
printf("if");
#elseif MOO == 8
printf("else if");
#else
printf("else");
#endif

#emit

Não aparece na tabela do pawn-lang.pdf, mas existe. É basicamente um compilador inline: se você conhece AMX, pode inserir opcodes diretamente no código. Sintaxe: #emit <opcode> <argumento>. O argumento pode ser um número (inteiro ou racional) ou um símbolo local/global (variáveis, funções ou rótulos). Consulte o Pawn Toolkit v3664 para a lista de opcodes.

#endif

Funciona como a chave de fechamento de um if. Tudo o que estiver entre #if e #endif é incluído condicionalmente.

#endinput, #endscript

Interrompem a inclusão do arquivo atual.

#error

Interrompe a compilação imediatamente exibindo uma mensagem customizada. Veja #assert para um exemplo.

#if

Faz para o pré-processador o que if faz para o código: permite escolher o que será compilado. Considere:

#define LIMIT 10

if (LIMIT < 10)
{
printf("Limit too low");
}

Isso vira:

if (10 < 10)
{
printf("Limit too low");
}

O compilador sabe que a condição é constante e avisa. Se o resultado nunca muda, por que manter o código? Remover o trecho impediria validações futuras caso LIMIT fosse alterado. É aí que #if ajuda: diferente de if, ele espera expressões constantes.

#define LIMIT 10

#if LIMIT < 10
#error Limit too low
#endif

Assim a checagem ocorre na compilação e evita código morto. Note que os parênteses são opcionais.

Outro exemplo:

#define LIMIT 10

#if LIMIT < 10
printf("Limit less than 10");
#else
printf("Limit equal to or above 10");
#endif

Somente o ramo válido é compilado, mas o código redundante permanece no arquivo para futuras mudanças.

#include

Insere o conteúdo de outro arquivo no ponto onde a diretiva aparece. Existem dois formatos:

  • Relativo ("arquivo.pwn"): o caminho é resolvido relativo ao arquivo atual.
  • Sistema (<arquivo>): o arquivo é buscado no diretório include ao lado (ou um nível acima) do compilador Pawn, como pawno/include.

Ambos aceitam subpastas:

#include "folder/me.pwn"
#include <folder/me>

Se o arquivo não existir, a compilação falha.

#pragma

Diretiva para ajustar o comportamento do compilador. Exemplo:

#pragma ctrlchar '$'

Isso altera o caractere de escape de \ para $. Algumas opções úteis no contexto SA:MP:

NomeValoresDescrição
codepagenome/valorDefine a página de código Unicode usada para strings.
compress1/0Não suportado no SA-MP.
deprecatedsímboloGera um aviso ao usar o símbolo indicado, sinalizando que existe versão melhor.
dynamicvalor (geralmente potência de 2)Define o tamanho (em células) da pilha e do heap; use ao receber avisos de memória insuficiente.
librarynome da DLLIndica a DLL da qual funções nativas serão importadas; não transforma o arquivo atual em biblioteca.
pack1/0Inverte o significado de !"" e "". Veja pawn-lang.pdf para detalhes sobre strings compactadas.
tabsizevalorDefine o tamanho do tab para evitar avisos errados de indentação; em SA:MP o padrão é 4. Não use 0, pois oculta avisos úteis.
unusedsímboloSuprime o aviso “symbol is never used” para o símbolo indicado. Útil quando stock não se aplica (por exemplo, parâmetros).

Depreciado

new
gOldVariable = 5;

#pragma deprecated gOldVariable

main() { printf("%d", gOldVariable); }

Gera um aviso indicando que gOldVariable não deve mais ser usada. Útil para manter compatibilidade enquanto a API evolui.

#tryinclude

Semelhante a #include, mas não falha se o arquivo não existir. Serve para incluir recursos opcionais quando o desenvolvedor possui o plugin apropriado.

myinc.inc

#if defined _MY_INC_INC
#endinput
#endif
#define _MY_INC_INC

stock MyIncFunc() { printf("Hello"); }

Gamemode

#tryinclude <myinc>

main()
{
#if defined _MY_INC_INC
MyIncFunc();
#endif
}

MyIncFunc só será chamada se myinc.inc estiver disponível e compilar sem erros.

#undef

Remove um macro ou símbolo constante previamente definido.

#define MOO 10
printf("%d", MOO);
#undef MOO
printf("%d", MOO); // erro: MOO não existe mais

Também funciona com enumeradores:

enum {
E_EXAMPLE = 300
};

printf("%d", E_EXAMPLE);
#undef E_EXAMPLE
printf("%d", E_EXAMPLE); // erro fatal