Ad Code

Responsive Advertisement

Retorno de strings e matrizes

 Embora as funções em Pawn normalmente retornem apenas valores simples do tamanho de uma célula, a linguagem permite que funções (mesmo nativas) retornem matrizes e, portanto, também strings. No entanto, o mecanismo que permite isso é um pouco mais complexo e pode não ser adequado para alguns casos de uso.


Em primeiro lugar, vamos examinar a maneira padrão de obter uma string de uma função.

Por meio de um parâmetro de saída
Todas as funções SA-MP nativas produzem uma string por meio de um parâmetro de matriz não const padrão. Como os arrays são passados ​​por referência (o que significa que a função obtém acesso à variável real e não apenas ao valor interno), a função nativa pode armazenar facilmente quaisquer dados dentro de:
Código de peão:
novo nome [ MAX_PLAYER_NAME + 1 ] ;
GetPlayerName ( playerid, name, sizeof name ) ;
Normalmente, outro parâmetro é usado junto com o parâmetro da matriz para especificar o comprimento da matriz. Em Pawn, não há uma maneira simples de obter o comprimento de um array diretamente no tempo de execução e, portanto, o compilador deve fornecer o comprimento quando necessário (o operador sizeof ). Para strings, uma célula extra deve ser alocada na matriz para armazenar o caractere nulo, indicando o fim da string (daí o + 1 ).

Essa maneira é especialmente útil para obter arrays de comprimento variável (como strings). função de formato , por exemplo, só pode ser implementada desta forma, pois o comprimento teórico da string de saída é ilimitado.

Retornando um array diretamente
Se você deseja produzir um tamanho fixo array, você pode retorná-lo de uma função diretamente:
Código de peão:
encaminhar [ MAX_PLAYER_NAME + 1 ] PlayerName ( playerid ) ;
estoque PlayerName ( playerid )
{
    novo nome [ MAX_PLAYER_NAME + 1 ] ;
    GetPlayerName ( playerid, name, sizeof name ) ; nome de
    retorno ;
}
A declaração de encaminhamento é opcional, mas é útil, pois faz com que você tenha em mente que o comprimento do array é importante.

Agora, se você conhece um pouco de outras linguagens como C etc., você deve estar ciente de que, como o nome é alocado na pilha, ele não existe mais quando a função retorna. Pawn supera esse fato usando um truque - quando a função é chamada, um espaço extra para o array é alocado e o endereço dessa variável é fornecido para a função por meio de um parâmetro secreto.

Na realidade, a função é parecida com esta:
Código de peão:
estoque PlayerName ( playerid, saída [ MAX_PLAYER_NAME + 1 ] )
{
    novo nome [ MAX_PLAYER_NAME + 1 ] ;
    GetPlayerName ( playerid, nome, sizeof nome ) ;
    output = name;
}
Como você pode ver, retornar uma string é apenas um atalho sintático conveniente para um parâmetro de saída extra.

No entanto, isso tem um custo de desempenho ligeiramente reduzido e bugs em certos casos. Vamos começar com os problemas:
Código de peão:
Selecione ações ( índice, arg [ ] , arg2 [ ] )
{
    if ( índice == 0 ) return arg;
    return arg2;
}
Esta função simples parece retornar um dos argumentos, mas como eles têm tamanhos indeterminados (representados como 0), o compilador pensa que essa função retorna um array de tamanho zero e não aloca nenhum espaço extra para a string. Você não pode retornar strings (ou arrays) de comprimento indeterminado e o compilador às vezes falha em informá-lo sobre isso.

Código de peão:
avançar [ 4 ] Func1 ( ) ;
estoque Func1 ( )
{
    new str [ ] = "abc" ;
    return str;
}

encaminhar [ 4 ] Func2 ( ) ;
estoque Func2 ( )
{
    retornar Func1 ( ) ;
}
Este código também está terrivelmente errado, mas de uma forma sutil. Func2 aloca espaço extra para o array retornado de Func1 , mas antes que o array possa ser copiado para o array de saída secreto da segunda função, ele é desalocado novamente e não está mais acessível.

Código de peão:
estoque Func ( ... )
{
    new str [ ] = "abc" ;
    return str;
}
O argumento de saída extra é colocado no final de todos os argumentos, mesmo após os variáveis. No entanto, o compilador não consegue obter corretamente o endereço de retorno nesse caso e assume que sua posição é constante.

Em todos esses casos, retornar uma string é uma coisa muito ruim de se fazer, já que o código geralmente compila bem e o problema só se torna aparente em tempo de execução.

Há um pequeno custo de desempenho associado ao retorno de matrizes também: o output = name; sempre acontece se a função é implementada em Pawn e, portanto, o array é copiado pelo menos uma vez. Dê uma olhada neste código:

Código de peão:
novo nome [ MAX_PLAYER_NAME + 1 ] ; // = PlayerName (playerid); não funciona, a atribuição direta não é suportada
name = PlayerName ( playerid ) ;
O compilador novamente aloca espaço extra para a string retornada de PlayerName (sempre na pilha), antes de movê -la para name . Portanto, a matriz deve ser copiada desnecessariamente duas vezes antes de ser utilizável.

Como você pode ver, o retorno de matrizes tem algumas desvantagens significativas, mas ainda é útil em alguns casos, quando você é cauteloso.
Código de peão:
format ( string, sizeof string, "Seu nome é% s." , PlayerName ( playerid ) ) ;
Este é o uso pretendido de retornar arrays - como argumentos temporários para outras funções. Em todos os outros casos, usar um parâmetro de saída normal é mais seguro e rápido. Nesse caso, nenhuma cópia extra acontece no site do chamador.

O próprio PlayerName pode ser "consertado" para retornar a string diretamente sem cópias desnecessárias, por meio de montagem in-line:
Código de peão:
avançar [ MAX_PLAYER_NAME + 1 ] PlayerName ( playerid ) ;
estoque PlayerName ( playerid )
{
    #assert MAX_PLAYER_NAME + 1 == 25
    #emit PUSH.C 25 // parâmetro de tamanho de GetPlayerName
    #emit PUSH.S 16 // parâmetro de retorno secreto de PlayerName no endereço 16 (& playerid + 4)
    #emit PUSH .S playerid // igual a 12
    #emit PUSH.C 12 // número de bytes passados ​​para a função (4 * 3 argumentos)
    #emit SYSREQ.C GetPlayerName // chamando a função
    #emit STACK 16 // limpeza dos argumentos da pilha
    #emit RETN
}
Dessa forma, PlayerName não faz nenhuma cópia extra, passando o endereço de retorno secreto diretamente para GetPlayerName . Strings

PawnPlus Strings
dinâmicas em PawnPlus oferecem a flexibilidade e conveniência dos valores normais, uma vez que são passados ​​como referências.
Código de peão:
estoque String : Func ( )
{
    return str_new ( "abc" ) ;
}
A string pode ser retornada de funções, passada para outras funções ou mesmo para funções nativas, inspecionada ou modificada, e tudo isso sem qualquer cópia adicional.

Strings constantes
Todos os métodos anteriores são adequados para strings que são produzidas em tempo de execução, mas para strings constantes, eu desaconselho o uso de qualquer um deles. Em vez disso, use macros.

Código de peão:
new const _tips [ ] [ ] = {
    "Dica um" ,
    "Dica dois" ,
    "Dica três" ,
    "Dica quatro"
} ;
#define RandomTip () (_tips [random (sizeof _tips)])
Usar isso em funções como SendClientMessage não requer nenhuma cópia da string, uma vez que o endereço da string é usado diretamente. Você também pode usar strings de comprimento variável na matriz, resultando em um armazenamento um pouco mais eficiente.

Postar um comentário

0 Comentários

© 2022 PawnScript All Rights Reversed