[Explicaciуn] Porque no usar 256 celdas.
#1

Porque no deberнas crear tus strings con 256 celdas.
por ******, traducciуn MrDeath
Contenidos
  • Contenidos
  • Introducciуn
  • Fondo
  • їPor quй no deberнas usar 256 celdas?
    • Porque es lento
    • No lo necesitas (1)
    • La mбxima entra es 128
    • La mбxima salida es 128
    • No lo necesitas (2)
    • Uso de apilaciуn
  • Strings comprimidos
  • їCuбndo deberнa usar 256 celdas?
    • SQL
    • Lectura de archivos
  • Conclusiуn
Introducciуn

Las personas tienen muchas visiones distintas sobre los strings en Pawn, mayormente con sus tamaсos. Mucha gente piensa que esos strings no pueden ser mayores a 256, їpor quй?, no lo sй. Pareciera que es un lнmite sin necesidad y en efecto el lнmite no existe. Otras personas piensan que esos strings tienen que tener 256 celdas para sin aparetne razуn. No importa que tan largo crйen el string, el string en PAWN es exactamente lo mismo que cualquier otro array (matrнz), parece que no tienen problemas con otros arrays (matrices)

Nota: la mayorнa de la gente usa ya sea 255 o 256, pero esos son equivalentes como basura como cualquier otro.

Fondo

Un string en Pawn es un array (matrнz) de caracteres, no diferente a cualquier otro array. Los strings son nulos terminados, esto significa que todos ellos tienen el caracter "\0" (nulo) al final (el cуdigo ASCII 0, es diferente a el caracter numйrico 0, el cuбl tiene el cуdigo ASCII 4. Si tenйs los siguientes strings:

pawn Код:
new str[5] = "hola";
Ocupa realmente 3 celdas (una para la "H", otra para la "O", para la "L", para la "A" y para el caracter nulo que significa que el string finalizу). Podrнas tambiйn escribirlo como:

pawn Код:
new str[5] = {'h', 'o', 'l', 'a', '\0'};
O tambiйn:

pawn Код:
new str[5] = {104, 111, 108, 97, 0}; // NO sй si estбn bien los caracteres, intentй escribirlos en base a la lуgica de los que puso ****** en su tutorial.
Cada uno de los nъmeros es un caracter ASCII, en este caso para representar cada una de las letras, y el 0 es el finalizador.

En PAWN todas las variables son establecidas a 0 cuando son declaradas/creadas, esto significa que cuando hacйs:

pawn Код:
new str[256];
Estбs realmente haciendo:

pawn Код:
new str[256];
for (new i = 0; i < 256; i ++)
{
    str[i] = 0;
}
Esto estб mбs optimizado que eso, pero toma mбs tiempo.

їPor quй no usar 256 celdas?
  • Es lento
Cуmo explicamos en la secciуn "Fondo", todas las variables son establecidas a 0 cuando las declaramos/creamos, a mayor cantidad de variables tengas mбs tiempo tomarбn para establecerse todas a 0.
Son optimizadas en el ensamblador de lнnea para hacerlo, no estбn interpretadas en Pawn. Pero esto significa que AMXModX escribiу otro operador, muy similar al "new", el cuбl declara una variable pero no la pone en blanco, para obtener este exacto problema.

[anchor=d1]
  • No lo necesitas (1)
Tomare este post que vн recientemente (esto me inspirу a escribir este post):

Quote:
Originally Posted by X_Cutterz
pawn Код:
stock ReturnModeratorCmd(playerid,reqlvl)
{
    new rmcmd[256];
    format(rmcmd,sizeof(rmcmd),"Solo los moderadores de mayor nivel a %d pueden usar este comando!",reqlvl);
    return SendClientMessage(playerid,Green,rmcmd);
}
Asumiremos que esos de allн son un maximo de 10000 (0 a 9999) niveles de administrador, El mayor nъmero para ser insertado dentro de este string tendrнa 4 caracteres.


Segъn mi cuenta son 69 caracteres en ese string, 2 de los cuales son "%d" no apareceran en el final del string, entonces son 67 en el final del string. Ya sabemos que tan largo puede ser el nъmero (4 dнgitos). Y sabemos que todos los strings requieren el caracter nulo al final, entonces la longitud del string puede ser esta:

69 - 2 + 4 + 1 = 72

72 celdas, entonces їpor quй usar 256?, es sуlo gastar 184 celdas (736 byes - Ўestб cerca de ser un kilobyte de memoria gastada!)
  • La mбxima entrada es 128
La mбxima entrada de texto en el chatbox del SA-MP es 128 caracteres, si escribнs cualquier cosa sabrбs que jamбs podremos superar 128 caracteres. Esto incluye los comandos, entonces їpara quй usar un tope del doble de tamaсo para procesar el texto?
  • La mбxima salida es 128
La mбxima salida de texto del chatbox en una misma linea es 128, si querйs probarlo enviб un mensaje a cualquiera, este no podrб exceder los 128 caracteres, entonces їpara quй crear un tope mayor a 128? Si usбs algъn texto de entrada (por ejemplo el comando "/me"), usar una variable con el tamaсo de 128 es recomendado porque no se sabe que tan largo puede ser lo que escriba el cliente. Pero sabйs que no puede ser mayor a 128.
  • No lo necesitas (2)
pawn Код:
public OnPlayerCommandText(playerid, cmdtext[])
{
    new string[256], cmd[256];
    cmd = strtok(cmdtext, idx);
    if (strcmp(cmd, "/num", true) == 0)
    {
        format(string, sizeof (string), "Numero aleatorio: %d", random(27));
        SendClientMessage(playerid, 0xFF0000AA, string);
    }
}
Allн esta la totalidad de cosas malas con ese cуdigo, pero unafortunadamente esto es un ejemplo de muchos problemas. Ignorando el factor que estбn usando strtok, eso integramente una cosa separada, sigue siendo un muy mal cуdigo:

pawn Код:
new string[256], cmd[256];
їPor quй dos? їPor quй necesitбs un string tan grande para un comando, y otro gran string para datos que usarбs luego de que sepas que comando fuй usado, y eso ya no es necesitado para la informaciуn en la variable del comando? Es reusarlo de lo contrario estarнas duplicando el tiempo para el punto 1.

pawn Код:
new string[256];
їPor quй 256? Cуmo explicamos arriba sabйs que la entrada jamбs podrнa ser mayor a 128. Si reusas la variable para la salida aunque sabйs que la salida no puede ser mayor a 128 caracteres, esto no es ineficiente porque como necesitбs una variable grande para almacenar toda la entrada si es requerido.

Una manera mбs eficiente de esta versiуn serнa.

pawn Код:
public OnPlayerCommandText(playerid, cmdtext[])
{
    new string[128]; // cmdtext jamбs serб mayor a 128
    string = strtok(cmdtext, idx);

    if (strcmp(string, "/num", true) == 0)
    {
        format(string, sizeof (string), "Numero aleatorio: %d", random(27)); // Sуlo necesitamos 21 caracteres aquн, pero 128 se necesita arriba, entonces el tamaсo de la variable estб justificado.
        SendClientMessage(playerid, 0xFF0000AA, string);
    }
}
  • Strings comprimidos
Cuando usбs una funciуn su memoria es puesta en una cosa llamada "stack", la memoria de la funciуn no puede estar puesta estбticamente porque una funciуn podrнa auto-usarse, requiriendo duplicar la memoria. Esta бrea de memoria es llamada memoria dinбmica. Ejemplo:

pawn Код:
new
    gVar = 2;

stock StackUse()
{
    new
        str[9];
    format(str, sizeof (str), "gVar = %d", gVar);
    SendClientMessageToAll(0xFF0000AA, str);
    if (gVar)
    {
        gVar--;
        StackUse();
    }
}
Esta funciуn sera usada uan vez y asigna 9 celdas en la compresiуn para este uso. Esto se usarб a el mismo y asignara otras 9 celdas, luego se usarб a el mismo y de nuevo alojarб otras 9 celdas. Luego de que esto fuй usado 3 veces serбn 27 celdas asignadas. Por el tercer uso "gVar" serб 0, entonces la funciуn dejarб de usarce a si misma y terminarб, removiendo estas 9 celdas. Estos pases de control vuelven a una instancia previa en la funciуn, la cual sуlo termina y remueve estas 9 celdas, como hizo la primera instancia de la funciуn, entonces ahora son 0 celdas en el "stack" para esta funciуn.

Ahora imaginб este cуdigo:

pawn Код:
new
    gVar = 2;

stock StackUse()
{
    new
        str[256];
    format(str, sizeof (str), "gVar = %d", gVar);
    SendClientMessageToAll(0xFF0000AA, str);
    if (gVar)
    {
        gVar--;
        StackUse();
    }
}
Exactamente lo mismo, pero como es puesta 3 veces por ella misma esto serнan 768 celdas (3072 bytes, 3 kilobytes) en el stack, comparado con 27 celdas (108 byes, 0.1 kilobytes, una reducciуn del 2800%) de la original.

A alguno de ustedes le ha pasado esto (o algo parecido) cuando compilaban:

Код:
Header size:      216 bytes
Code size:       776 bytes
Data size:       528 bytes
Stack/heap size:   16384 bytes; estimated max. usage: unknown, due to recursion
Total requirements:  17904 bytes
O tambiйn:

Код:
Header size:      200 bytes
Code size:       588 bytes
Data size:       512 bytes
Stack/heap size:   16384 bytes; estimated max. usage=10250 cells (41000 bytes)
Total requirements:  17684 bytes
Esto significa que el compilador detecto que estбs usando mas memoria stack de la que estб disponible. Un montуn de informaciуn importante es guardada en el stack, como quiйn la usу. Si usбs demasiada memoria porque la informaciуn es guardada no podйs sobre-escribir la informaciуn de stack, retornando algo raro y posiblemente crashйe. Entonces tendrбs memoria falsa porque es sobre-escrita por otros datos. Cuando las personas tienen este mensaje la advertencia comъn es usar "#pragma dynamic", la cuбl no es una soluciуn.

El primer error que postiй significa que estбs intentado usar mбs memoria de la disponible, pero porque allн la funciуn esta auto-usandose el compilador no puede decir exactamente cuando memoria mбs. El compilador no puede saber cuantas veces se usa, como en el ejemplo de arriba podrнan cambiar los nъmeros. El segundo error fue generado por alguna acciуn sin recursiуn.

Esto se aplica a TODOS los arrays, pero los strings tienen mayor culpabilidad.

Strings comprimidos

Una caracterнstica del PAWN raramente usada en SA-MP es comprimir strings. Los strings regulares guardan un caracter por celda y cada una ocupa 4 bytes (haciendo que las celdas de 256 sean 1 kilobyte). Los strings comprimidos guardan 4 caracteres por celda:

Descomprimido:

pawn Код:
new
    string[13] = "Hola a todos!"; // 13 celdas, 52 bytes

Comprimido:

pawn Код:
new
    string[13 char] = !"Hola a todos!"; // 4 cells, 16 bytes
Esos strings estan bien documentados en "pawn-lang.pdf" entonces no irй a entrar en mucho detalle sobre ello, pero si tenйs largos arrays (matrices) de strings para guardar podrнa ser mejor que los comprimas. Si este mйtodo fuese usado en el ejemplo de arriba "ReturnModeratorCmd", combinado con un uso tamaсo decente del string podrнa haber reducido el uso de memoria de 1 kilobyte (1024 bytes) a 50 byes, eso es una reducciуn de 2000%.

їCuбndo deberнa usar 256 celdas?

Habiendo dicho esto, en algunos casos usar arrays grandes podria ser ъtil, pero deberнan ser sуlo usados cuando sea necesario.
  • SQL
Las querys SQL pueden ser bastante largas, por lo que necesitamos un string de por lo menos 1024 celdas en tamaсo para contenerlas. Como siempre is una extensiуn de "No lo necesitas", pero acб lo necesitбs.

  • Lectura de archivos
Este es un ejemplo de una introducciуn ilimitada. Si leйs una lнnea de un archivo no tenйs camino a saber que tan largo es. Y asignando una memoria ajustada no como en la entrada de texto del chat, esto podrнa tener cualquier tamaсo. Serнa adecuado usar un nъmero redondo como 256 para cubrir las eventualidades.

Conclusiуn


En muy pocos casos son necesitados arrays (matrices) grandes, piensa en determinar cuбnta memoria necesitбs para el array (matrнz) basandote en cuбnto necesitбs para aplicar los strings.
Reply
#2

linda traduccion, despues la leo detenidamente xq ahora estoy haciendo otras cosas. xD
Reply
#3

Si les interezу el tutorial, y desean optimizar sus scripts, hice un programa MEGA SIMPLE en VisualBasic6 para saber cuantos caracteres tiene un texto, asн podrбn utilizar el tamaсo requerido.

Longitud del texto
Longitud del texto - Source

Imagen:
Reply
#4

lindo programita che realmente muy utiles para los vagos (x no decir otra cosa) como vos y yo q no se gastan en contar para usar el tamaсo adecuado xD.
Reply
#5

Wow, gracias por la Traduccion.
Si, realmente casi todos los RP tienen la fama de usar celdas innecesarias.
Me llevo el programa Sera de utilidad

Saludos
Reply
#6

Esto es muy comъn de ver en un script cualquiera:
pawn Код:
public OnPlayerConnect(playerid)
{
    new string[256];
    format(string, sizeof(string), "%d", playerid);
    for(new i = 0; i < MAX_PLAYERS; i ++)
    {
        SendClientMessage(i, 0xFFFFFF, string);
    }
    return 1;
}
Reply
#7

Quote:
Originally Posted by MrDeath
Посмотреть сообщение
Ocupa realmente 3 celdas
No, ocupa 5 celdas, si ocupase 3 celdas, cuando tu imprimieses "str" se verнa asн "hol", y posiblemente te diese, "array out of bounds"
Код:
'H'   ---1 -0
'o'   ---2 -1
'l'   ---3 -2
'a'   ---4 -3
'\0'  ---5 -4
Por lo demбs, buena traducciуn.
Reply
#8

Exelente!, ya no mas GM que causan lentitud, lagg, y menos capacidad!!. Yo siempre explicaba esto por MSN pero nadie me entendia, haora tirare este post para que lo vean xd!
Reply
#9

Muy buena la traduccion y en yapa el programita :P
Reply
#10

Perdуn Cesar cuando lo traducн capбs se me pasу por alto, porque tambiйn "intentar" poner ejemplos en espaсol, quizб en algo fallй.

EDIT: Y gracias a los otros por los comentarios
Reply
#11

exelente Info! : )
Reply
#12

Jeje eso una vez me explico un colega y en el colegio pero yo siempre usare string[256].
Una vez intente acostumbrarme a no poner el 256 pero me dio 'paja' y desde entonces cuando me acuerdo (casi nunca) coloco el string debjo de OnPlayerCommandText
Reply
#13

Quote:
Originally Posted by GROVE4L
Посмотреть сообщение
Jeje eso una vez me explico un colega y en el colegio pero yo siempre usare string[256].
Una vez intente acostumbrarme a no poner el 256 pero me dio 'paja' y desde entonces cuando me acuerdo (casi nunca) coloco el string debjo de OnPlayerCommandText
No es muy dificil aconstumbrarse a no usar 256, y es bastante mejor, para tu nivel de scripting deberнas hacerlo :P
Reply
#14

Yo tengo una duda ._.

Perdonen si revivi xD

Bueno, mi duda es esta, hace poco the_chaoz me hizo el favor de arreglar un comando de /advertir pero este cuando escribo la razуn sale de esta forma, si pongo "No Dm" en el chat sale "No." Sуlo las 2 primeras letras, el code de string y ad son estos

pawn Код:
if(!strcmp(cmd, "/ad", true)){

        tmp[0] = strtok(cmdtext, idx);
        tmp[1] = strtok(cmdtext, idx);
        if(!strlen(tmp[0]) || !strlen(tmp[1]))return SendClientMessage(playerid, COLOR_ROJO, "Usa: /ad [ID] [Razon].");
        new id;
        new str[128];
        id = strval(tmp[0]);
        if(IsPlayerConnected(id)){
            new name[2][MAX_PLAYER_NAME];
            GetPlayerName(playerid, name[0], MAX_PLAYER_NAME);
            GetPlayerName(id, name[1], MAX_PLAYER_NAME);
            Advertido[id]++;
            format(str, 128, "%s ha sido advertido (Razon: %s)(%i/3)", name[1], tmp[1], Advertido[id]);
            SendClientMessage(playerid, COLOR_AZUL, str);
            format(str, 128, "Has sido advertido por %s. (Razon: %s.)(%i/3)", name[0], tmp[1], Advertido[id]);
            SendClientMessage(id, COLOR_VERDE_CLARO, str);
            format(str, 128, "%s ha sido advertido por %s. (Razon: %s.) (%i/3)", name[1], name[0], tmp[1], Advertido[id]);
            SendClientMessageToAll(COLOR_NARANJA, str);
            PlayerPlaySound(playerid, 1057, 0.0, 0.0, 0.0);
            PlayerPlaySound(id, 1057, 0.0, 0.0, 0.0);
            if(Advertido[id] >= 3)Kick(id);
            return 1;
        }return SendClientMessage(playerid, COLOR_ROJO, "El jugador no se encuentra conectado.");
    }
Yo digo que es el String ya que cada vez qe lo modifico cambia, pero nunca se muestra correctamente como quisiera en "razуn"

Perdonen si esto no va aquн, pero hablando de strings xD
Reply
#15

Quote:
Originally Posted by Lunnatiicz
Посмотреть сообщение
Yo tengo una duda ._.

Perdonen si revivi xD

Bueno, mi duda es esta, hace poco the_chaoz me hizo el favor de arreglar un comando de /advertir pero este cuando escribo la razуn sale de esta forma, si pongo "No Dm" en el chat sale "No." Sуlo las 2 primeras letras, el code de string y ad son estos

pawn Код:
if(!strcmp(cmd, "/ad", true)){

        tmp[0] = strtok(cmdtext, idx);
        tmp[1] = strtok(cmdtext, idx);
        if(!strlen(tmp[0]) || !strlen(tmp[1]))return SendClientMessage(playerid, COLOR_ROJO, "Usa: /ad [ID] [Razon].");
        new id;
        new str[128];
        id = strval(tmp[0]);
        if(IsPlayerConnected(id)){
            new name[2][MAX_PLAYER_NAME];
            GetPlayerName(playerid, name[0], MAX_PLAYER_NAME);
            GetPlayerName(id, name[1], MAX_PLAYER_NAME);
            Advertido[id]++;
            format(str, 128, "%s ha sido advertido (Razon: %s)(%i/3)", name[1], tmp[1], Advertido[id]);
            SendClientMessage(playerid, COLOR_AZUL, str);
            format(str, 128, "Has sido advertido por %s. (Razon: %s.)(%i/3)", name[0], tmp[1], Advertido[id]);
            SendClientMessage(id, COLOR_VERDE_CLARO, str);
            format(str, 128, "%s ha sido advertido por %s. (Razon: %s.) (%i/3)", name[1], name[0], tmp[1], Advertido[id]);
            SendClientMessageToAll(COLOR_NARANJA, str);
            PlayerPlaySound(playerid, 1057, 0.0, 0.0, 0.0);
            PlayerPlaySound(id, 1057, 0.0, 0.0, 0.0);
            if(Advertido[id] >= 3)Kick(id);
            return 1;
        }return SendClientMessage(playerid, COLOR_ROJO, "El jugador no se encuentra conectado.");
    }
Yo digo que es el String ya que cada vez qe lo modifico cambia, pero nunca se muestra correctamente como quisiera en "razуn"

Perdonen si esto no va aquн, pero hablando de strings xD
no el problema no es ese. el problema es mi animalada xD supongo q asi va a funcionardigo supongo xq los cmd con parametros uso dcmd :P)

pawn Код:
if(!strcmp(cmd, "/ad", true)){
    new tmp[2][256];
    tmp[0] = strtok(cmdtext, idx);
    tmp[1] = strtok(cmdtext, idx);
    if(!strlen(tmp[0]) || !strlen(tmp[1]))return SendClientMessage(playerid, COLOR_ROJO, "Usa: /ad [ID] [Razon].");
    new id;
    new str[128];
    id = strval(tmp[0]);
    if(IsPlayerConnected(id)){
        new name[2][MAX_PLAYER_NAME];
        GetPlayerName(playerid, name[0], MAX_PLAYER_NAME);
        GetPlayerName(id, name[1], MAX_PLAYER_NAME);
        Advertido[id]++;
        format(str, 128, "%s ha sido advertido (Razon: %s)(%i/3)", name[1], cmdtext[5+strlen(tmp[0])], Advertido[id]);
        SendClientMessage(playerid, COLOR_AZUL, str);
        format(str, 128, "Has sido advertido por %s. (Razon: %s.)(%i/3)", name[0], cmdtext[5+strlen(tmp[0])], Advertido[id]);
        SendClientMessage(id, COLOR_VERDE_CLARO, str);
        format(str, 128, "%s ha sido advertido por %s. (Razon: %s.) (%i/3)", name[1], name[0], cmdtext[5+strlen(tmp[0])], Advertido[id]);
        SendClientMessageToAll(COLOR_NARANJA, str);
        PlayerPlaySound(playerid, 1057, 0.0, 0.0, 0.0);
        PlayerPlaySound(id, 1057, 0.0, 0.0, 0.0);
        if(Advertido[id] >= 3)Kick(id);
        return 1;
    }return SendClientMessage(playerid, COLOR_ROJO, "El jugador no se encuentra conectado.");
}
Reply
#16

The_Chaoz me funciono perfecto

Pero me podrias decir cuбl fue el error?

Asн avito futuras "animaladas" xd
Reply
#17

q strtok x defecto funciona como un split x asi decirlo. retorna la 1 cadena anterior a " " despues del intex definido. x eso solo te retornaba la 1є palabra de la razon. si vos ponias la razon toda junta la iva a mostrar. fue mi error perdon.
Reply
#18

Excelente tuto
Reply
#19

Es muy interesante, y lo revivo precisamente por que me intereso mucho y quisiera que mas personas leyeran esto.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)