Ir al contenido


Foto

BASE64


  • Por favor identifícate para responder
12 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 18 marzo 2016 - 06:06

Preguntaron como codificar y descodificar una imagen en BASE64 sin utilizar la API, como había hecho en este hilo, se trataba de usarlo en un entorno ajeno a Windows (Android). Al leer la pregunta no pude resistirme a implementar mi propia versión sin grandes pretensiones, usando pascal sin las facilidades de la VCL.

 

BASE64 se basa a usar los bytes de un buffer en conjuntos de 6 bits, de forma que el mayor número es el 111111b es decir, 63 en decimal. A cada valor obtenido se le asigna un carácter de un alfabeto de 64 caracteres. Si faltan bits se añaden ceros y se codifican con uno o dos caracteres '=' (según falten 8 ó 16 bits) para informar al decodificador. La decodificación es a la inversa.
 
El tamaño del buffer de salida codificado, cuando no se introducen retornos de carro y línea se puede calcular así: ((L+2) div 3)*4. Y cuando se decodifica el tamaño será (L*3) div 4. El decodificador debe ignorar cualquier carácter que no esté en el alfabeto.
 
Escribí el código en una unit que publico a continuación:


delphi
  1. unit BASE64;
  2.  
  3. interface
  4.  
  5. type
  6. TAByte = Array of Byte;
  7. PAByte = ^TAByte;
  8.  
  9. function Decode64(var S: String): TAByte;
  10. function Encode64(Bin: PByte; Count: integer): String;
  11.  
  12. implementation
  13.  
  14. const
  15. SB64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  16. IB64: array[#0..#255] of integer = (
  17. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  18. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  19. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $3E, $FF, $FF, $FF, $3F,
  20. $34, $35, $36, $37, $38, $39, $3A, $3B, $3C, $3D, $FF, $FF, $FF, $FF, $FF, $FF,
  21. $FF, $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0D, $0E,
  22. $0F, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $FF, $FF, $FF, $FF, $FF,
  23. $FF, $1A, $1B, $1C, $1D, $1E, $1F, $20, $21, $22, $23, $24, $25, $26, $27, $28,
  24. $29, $2A, $2B, $2C, $2D, $2E, $2F, $30, $31, $32, $33, $FF, $FF, $FF, $FF, $FF,
  25. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  26. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  27. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  28. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  29. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  30. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  31. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  32. $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  33. );
  34.  
  35. type
  36. SAByte = Array[0..0] of Byte;
  37. PSAByte = ^SAByte;
  38.  
  39. function Decode64(var S: String): TAByte;
  40. var
  41. B: array[0..3] of BYTE;
  42. L, n, i, j: integer;
  43. begin
  44. n:= 1;
  45. i:= 0;
  46. L:= Length(S);
  47. if L < 4 then exit;
  48. while S[L] = '=' do dec(L);
  49. SetLength(Result, (L*3) div 4);
  50. repeat
  51. for j:= 0 to 3 do
  52. begin
  53. while (n < L) and (IB64[S[n]] = $FF) do inc(n); B[j]:= IB64[S[n]]; inc(n);
  54. end;
  55. Result[i]:= (B[0] shl 2) or (B[1] shr 4);
  56. if B[2] = 255 then break;
  57. Result[i+1]:= (B[1] shl 4) or (B[2] shr 2);
  58. if B[3] = 255 then break;
  59. Result[i+2]:= (B[2] shl 6) or B[3];
  60. inc(i, 3);
  61. until n > L;
  62. end;
  63.  
  64. function Encode64(Bin: PByte; Count: integer): String;
  65. var
  66. B0, B1, B2: BYTE;
  67. ABin: PSAByte;
  68. L, n, i: integer;
  69. begin
  70. if Count = 0 then exit;
  71. ABin:= PSAByte(Bin);
  72. n:= 0;
  73. i:=1;
  74. L:= ((Count+2) div 3)*4;
  75. SetLength(Result, L);
  76. repeat
  77. B0:= ABin^[n];
  78. B1:= 0; B2:= 0;
  79. if (Count - n) > 0 then B1:= ABin^[n+1];
  80. if (Count - n) > 1 then B2:= ABin^[n+2];
  81. Result[i]:= SB64[(B0 shr 2) and $003F +1];
  82. Result[i+1]:= SB64[((B0 shl 4) or (B1 shr 4)) and $3F +1];
  83. Result[i+2]:= SB64[((B1 shl 2) or (B2 shr 6)) and $3F +1];
  84. Result[i+3]:= SB64[(B2 and $3F) +1];
  85. inc(n,3);
  86. inc(i,4);
  87. until n >= Count;
  88. if n - Count >= 1 then Result[L]:= '=';
  89. if n - Count = 2 then Result[L-1]:= '=';
  90. end;
  91.  
  92. end.

Si deseamos usar este código para trabajar con stream sin modificar la unit, podemos implementar estas dos funciones añadidas en otra unit:


delphi
  1. function StreamEncode64(MStream: TMemoryStream): string;
  2. begin
  3.   Result:= Encode64(MStream.Memory, MStream.Size);
  4. end;
  5.  
  6. procedure StreamDencode64(var S: String; MStream: TMemoryStream);
  7. var
  8.   Bytes: TAByte;
  9. begin
  10.   Bytes:= Decode64(S);
  11.   MStream.SetSize(Length(Bytes));
  12.   Move(Bytes[0], MStream.Memory^, Length(Bytes));
  13.   SetLength(Bytes,0);
  14. end;

Espero que sea de utilidad.

 

 

Saludos.


  • 4

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 18 marzo 2016 - 09:41

Muy interesante, nunca me he puesto a estudiar este tipo de algoritmos

 

Solo tengo una duda, porque en el procedimiento StreamDencode64 pasas el string por referencia (calificador var)

 

Yo soy bastante obsesivo con los parametros de los metodos y funciones; siempre que sea posible utilizo const, por cuestiones de cohesion y de eficiencia.


  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 marzo 2016 - 06:34

Muy interesante, nunca me he puesto a estudiar este tipo de algoritmos

 

Solo tengo una duda, porque en el procedimiento StreamDencode64 pasas el string por referencia (calificador var)

 

Yo soy bastante obsesivo con los parametros de los metodos y funciones; siempre que sea posible utilizo const, por cuestiones de cohesion y de eficiencia.

 Elegí el paso por referencia para evitar la copia previa que el compilador ha de hacer. Teniendo en cuenta que la función ni StreamDencode64 ni Dencode64 escriben en la cadena pasada, me pareció más interesante este tipo de paso.

 

Si bien veo que en la versión de la unit se declara así:


php
  1. function Decode64(S: String): TAByte;

Cuando mi intención era esta:


php
  1. function Decode64(var S: String): TAByte;

Saludos.


  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 19 marzo 2016 - 08:29

Yo la verdad es que nunca me puse a estudiar este tema, voy a hacer unas preguntas muy tontas:

¿Cuándo, sobre que, y para que es conveniente codificar en Base64? He leído que se suele usar para "comprimir" imágenes, o también se la usa en MIME. Más o menos entiendo que lo que se hace es leer de a grupos de bits y generar una versión "textual" Pero... o es que no le capto la idea... ¿El objetivo es cifrar algo? Porque de serlo, no es lo mismo cifrar que codificar ¿que no?

 

Me llama la atención porque supuestamente es muy difundido su uso, y yo estoy en blanco.

 

Saludos,


  • 0

#5 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 19 marzo 2016 - 03:31

Justamente por eso era mi duda

En Delphi el tipo string pertenece a los "managed types", es decir, el manejo de memoria es automático, implementado mediante reference counting, tal y como las interfaces y los record

Al pasar un string usando const se obtiene la máxima eficiencia ya que lo que se pasa es la referencia del string, y además el compilador no inserta la llamada a .AddRef y .DecRef entre el inicio y final del método

Para cifrar que yo sepa no sirve, es simplemente una codificación
  • 0

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 marzo 2016 - 06:35

Justamente por eso era mi duda

En Delphi el tipo string pertenece a los "managed types", es decir, el manejo de memoria es automático, implementado mediante reference counting, tal y como las interfaces y los record

Al pasar un string usando const se obtiene la máxima eficiencia ya que lo que se pasa es la referencia del string, y además el compilador no inserta la llamada a .AddRef y .DecRef entre el inicio y final del método

Para cifrar que yo sepa no sirve, es simplemente una codificación

 
Me alegra que hagas esta aclaración porque desconocía que pasar como constante un string significaba pasarlo también por referencia. Estoy acostumbrado a trabajar con C/C++. En C++ existe el paso por referencia, paso de una referencia a una constante, paso de un puntero constante o paso de un puntero a un valor constante, si bien en C (no C++) no existe el concepto referencia lo que significa que el paso por referencia se hace con punteros. Siempre pensé que en lo posible sería igual en delphi aunque con menos variabilidad. En C/C++ lo tienes que especificar y no de da por "entendido".
 
Delphius, como indica Agustin Ortu, se trata de una codificación a texto y no comprime, sino que expande. Tiene su uso en la codificación para la identificación en el protocolo SMTP y proxys, por ejemplo. También se usa para enviar imágenes por red en muchas ocasiones. En general su uso está orientado al envío de binarios en protocolos dirigidos a texto. El inconveniente es que expande los binarios en una relación de 3 a 4 (24 bits se expanden a 32).

 

Saludos.


  • 0

#7 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 19 marzo 2016 - 07:57

 
Me alegra que hagas esta aclaración porque desconocía que pasar como constante un string significaba pasarlo también por referencia. Estoy acostumbrado a trabajar con C/C++. En C++ existe el paso por referencia, paso de una referencia a una constante, paso de un puntero constante o paso de un puntero a un valor constante, si bien en C (no C++) no existe el concepto referencia lo que significa que el paso por referencia se hace con punteros. Siempre pensé que en lo posible sería igual en delphi aunque con menos variabilidad. En C/C++ lo tienes que especificar y no de da por "entendido".

 

En las versiones mas nuevas se fue expandiendo mas este aspecto, en la docwiki hay mas info; por ejemplo se puede usar el atributo [Ref] para [forzar] pasar un parametro const por referencia

 

Esto es porque a veces el codigo producido por el compilador podria no ser el mas optimo, pero por otro lado (mencione mas arriba "cohesion") se quiere preservar la inmutabilidad  (solo lectura)

 

Como dije, yo soy obsesivo con este tema de los parametros, y siempre que sea posible utilizo const u out, ya que de alguna manera transmite cierta intencion (este parametro es de solo lectura, por eso es const; en este parametro tendrias que almacenar el resultado de Y, por eso es out)

 

-----

No estaba al tanto del detalle de el binario resultante del bas64 crecia, crei que al ser tan popular (sobre todo para mandar imagenes)

 

A nivel de performance en la codificacion/decodificacion como se comporta el algoritmo base64? Quizas los bytes de peso aumentados justifiquen que sea muy rapido

 

Saludos


  • 1

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 19 marzo 2016 - 08:39

Hola, éste es un tema excelente pero además lo que comenta Agustín es algo que suelo hacer cuando estoy creando mis clases, toda función o procedimiento que hag y que requiera de  enviar parámetros los asigno como const, normalmente no uso out a menos que tenga un procedimiento que necesite regresar un valor, o que una función requiera de mas de un valor de regreso, los var es muy raro que los utilice.

 

Lo dicho, éste es un tema muy bueno y aderezado con explicaciones excelentes y contundentes. (y)

 

Saludo


  • 1

#9 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 20 marzo 2016 - 10:20

Me gusta comprobar las cosas por mi mismo en lo posible, así que he hecho unas pruebas de código en delphi7 y viendo lo que pasa con los punteros y a nivel asm.
 
Primera prueba, paso por valor de un String:


delphi
  1. procedure foo(S: String);
  2. var
  3. S2: string;
  4. begin
  5. S2:= S;
  6. end;
  7.  
  8. var
  9. S: String;
  10. begin
  11. S:= '1';
  12. foo(S);
  13. end.

El resultado es que el puntero de S cambia al entrar en foo, como era de esperar. La llamada a foo se realiza por valor así:


delphi
  1. mov eax, [S]
  2. call foo

Una vez en foo se realiza una copia de S con una llamada call @LStrAddRef y un borrado de la copia con call @LstrClr al final antes de la salida ret.


 
Segunda prueba, paso por referencia de un String:


delphi
  1. procedure foo(var S: String);
  2. var
  3. S2: string;
  4. begin
  5. S2:= S;
  6. end;
  7.  
  8. var
  9. S: String;
  10.  
  11. begin
  12. S:= '1';
  13. foo(S);
  14. end.

El resultado es que el puntero de S es el mismo al entrar en foo, como era de esperar, dado que el paso por referencia es el paso por puntero. La llamada a foo se realiza por referencia así:
 


delphi
  1. mov eax, $00408294
  2. call foo

Siendo $00408294 el valor del puntero @S.
Una vez en foo no se realiza copia alguna de S y sigue su ejecución hasta ret.

 
Tercera prueba, paso como constante de un String:
 


delphi
  1. procedure foo(const S: String);
  2. var
  3.   S2: string;
  4. begin
  5.   S2:= S;
  6. end;
  7.  
  8. var
  9.   S: String;
  10.  
  11. begin
  12.   S:= '1';
  13.   foo(S);
  14. end.

El resultado es que el puntero de S cambia al entrar en foo luego ¡no se pasa por referencia!. La llamada a foo se realiza por valor así:


delphi
  1. mov eax, [S]
  2. call foo

Una vez en foo se realiza ¡no se realiza copia alguna de S! careciendo de las llamadas call @LStrAddRef al inicio y call @LstrClr al final, antes de la salida ret.

 

 

Conclusiones:

 

1,- El paso del parámetro de un String como constante es un paso por valor en el que el compilador no realiza copia alguna del mismo, resultando casi un equivalente del paso por referencia, siendo más corto el clásico paso por referencia.

 

2.- El paso como constante, es por tanto más ortodoxo que el paso por referencia cuando no se pretende cambiar el valor del parámetro pasado.

 

3.- El paso por referencia resulta un poco más rápido en ciclos que el paso por constante de un String pudiendo ser despreciable en una sola llamada.

 

 

 

Saludos.
 


  • 3

#10 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 20 marzo 2016 - 10:23

:|


  • 0

#11 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 22 marzo 2016 - 09:44

Aca va mi aporte en Delphi 2010
 
Primero el programa de consola que use para las pruebas, es basicamente las 3 funciones que comentó escafandra
 


delphi
  1. uses
  2. SysUtils;
  3.  
  4. procedure Valor(S: string);
  5. var
  6. S1: string;
  7. begin
  8. S1 := S;
  9. end;
  10.  
  11. procedure Referencia(var S: string);
  12. var
  13. S2: string;
  14. begin
  15. S2 := S;
  16. end;
  17.  
  18. procedure Constante(const S: string);
  19. var
  20. S3: string;
  21. begin
  22. S3 := S;
  23. end;
  24.  
  25. var
  26. S: string;
  27.  
  28. begin
  29. try
  30. S := '1';
  31. Valor(S);
  32. Referencia(S);
  33. Constante(S);
  34. Readln;
  35. except
  36. on E: Exception do
  37. Writeln(E.ClassName, ': ', E.Message);
  38. end;
  39.  
  40. end.

Luego, este es el código asm generado:


php
  1. Project1.dpr.33: S := '1';
  2. 004101AC B86C6E4100       mov eax,$00416e6c
  3. 004101B1 BA70024100       mov edx,$00410270
  4. 004101B6 E8F95EFFFF       call @UStrAsg
  5.  
  6. Project1.dpr.34: Valor(S);
  7. 004101BB A16C6E4100       mov eax,[$00416e6c]
  8. 004101C0 E827E2FFFF       call Valor
  9.  
  10. Project1.dpr.11: S1 := S;
  11. 0040E410 8D45F8           lea eax,[ebp-$08]
  12. 0040E413 8B55FC           mov edx,[ebp-$04]
  13. 0040E416 E8ED7CFFFF       call @UStrLAsg
  14.  
  15. Project1.dpr.35: Referencia(S);
  16. 004101C5 B86C6E4100       mov eax,$00416e6c
  17. 004101CA E875E2FFFF       call Referencia
  18.  
  19. Project1.dpr.18: S2 := S;
  20. 0040E45A 8D45FC           lea eax,[ebp-$04]
  21. 0040E45D 8B13             mov edx,[ebx]
  22. 0040E45F E8A47CFFFF       call @UStrLAsg
  23.  
  24. Project1.dpr.36: Constante(S);
  25. 004101CF A16C6E4100       mov eax,[$00416e6c]
  26. 004101D4 E8AFE2FFFF       call Constante
  27.  
  28. Project1.dpr.25: S3 := S;
  29. 0040E49E 8D45FC           lea eax,[ebp-$04]
  30. 0040E4A1 8BD3             mov edx,ebx
  31. 0040E4A3 E8607CFFFF       call @UStrLAsg

Seria interesante ver la misma prueba en compiladores mas modernos :)

 

 

 


  • 0

#12 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 22 marzo 2016 - 09:59

En el caso de las interfaces la cosa cambia :)
 
En esta ocasion este es el programa:
 


delphi
  1. type
  2. ITest = interface
  3.  ['{22000E45-F890-4293-8599-6651627718A6}']
  4.   procedure Test;
  5.  end;
  6.  
  7. TTest = class(TInterfacedObject, ITest)
  8. procedure Test;
  9. end;
  10.  
  11. procedure Valor(T: ITest);
  12. begin
  13.   T.Test;
  14. end;
  15.  
  16. procedure Referencia(var T: ITest);
  17. (*) begin
  18.   T.Test;
  19. end;
  20.  
  21. procedure Constante(const T: ITest);
  22. (*) begin
  23.   T.Test;
  24. end;
  25.  
  26. { TTest }
  27. procedure TTest.Test;
  28. begin
  29.   Writeln('Testing');
  30. end;
  31.  
  32. var
  33.   T: ITest;
  34. begin
  35.   T := TTest.Create;
  36.   try
  37.     Valor(T);
  38.     Referencia(T);
  39.     Constante(T);
  40.     Readln;
  41.   except
  42.     on E: Exception do
  43.       Writeln(E.ClassName, ': ', E.Message);
  44.   end;
  45. end.

Ya a simple vista se puede apreciar el resultado; al compilar, no se permite colocar un punto de ruptura en donde marque con * en el codigo, justo en la palabra begin; en el caso del pasaje por valor si se puede
 
El codigo ASM: 
 


delphi
  1. Project1.dpr.45: Valor(T);
  2. 004101CB A16C6E4100       mov eax,[$00416e6c]
  3. 004101D0 E8ABE5FFFF       call Valor
  4.  
  5. Valor(T)
  6. 0040E780 55               push ebp
  7. 0040E781 8BEC             mov ebp,esp
  8. 0040E783 51               push ecx
  9. 0040E784 8945FC           mov [ebp-$04],eax
  10. 0040E787 8B45FC           mov eax,[ebp-$04]
  11. 0040E78A E8C99BFFFF       call @IntfAddRef
  12. 0040E78F 33C0             xor eax,eax
  13. 0040E791 55               push ebp
  14. 0040E792 68BBE74000       push $0040e7bb
  15. 0040E797 64FF30           push dword ptr fs:[eax]
  16. 0040E79A 648920           mov fs:[eax],esp
  17. Project1.dpr.19: T.Test;
  18. 0040E79D 8B45FC           mov eax,[ebp-$04]
  19. 0040E7A0 8B10             mov edx,[eax]
  20. 0040E7A2 FF520C           call dword ptr [edx+$0c]
  21.  
  22. Project1.dpr.46: Referencia(T);
  23. 004101D5 B86C6E4100       mov eax,$00416e6c
  24. 004101DA E8E9E5FFFF       call Referencia
  25.  
  26. Referencia(T)
  27. 0040E7C8 8B00             mov eax,[eax]
  28. 0040E7CA 8B10             mov edx,[eax]
  29. 0040E7CC FF520C           call dword ptr [edx+$0c]
  30.  
  31. Project1.dpr.47: Constante(T);
  32. 004101DF A16C6E4100       mov eax,[$00416e6c]
  33. 004101E4 E8E7E5FFFF       call Constante
  34.  
  35. Constante(T)
  36. 0040E7D0 8B10             mov edx,[eax]
  37. 0040E7D2 FF520C           call dword ptr [edx+$0c]

En este caso la diferencia entre el usar var/const contra valor si es notable; aunque entre var y const es bastante despreciable (similar al caso de los strings)
 
Esta respuesta de SO arroja algo de luz (enlace)
 
Tiene sentido que en el anterior caso de los string el const no implicaba mucho en la performance porque estabamos asignando en otra variable string. Por lo tanto si se estaba produciendo el "try-finally" oculto para incrementar/decrementar el contador de referencias


  • 0

#13 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 22 marzo 2016 - 10:13

Por ultimo y tomando como conclusion el post anterior, en el cual el secreto de los parametros const para tipos con contador de re referencias es no producir que se cambie la cantidad de referencias de ninguna manera (por ejemplo al asignar la variable), propongo la siguiente variante para la prueba con strings:
 
 
Programa:

delphi
  1. procedure Valor(S: string);
  2. begin
  3. Writeln(S);
  4. end;
  5.  
  6. procedure Referencia(var S: string);
  7. begin
  8. Writeln(S);
  9. end;
  10.  
  11. procedure Constante(const S: string);
  12. begin
  13. Writeln(S);
  14. end;
  15.  
  16. var
  17. S: string;
  18. begin
  19. try
  20. S := '1';
  21. Valor(S);
  22. Referencia(S);
  23. Constante(S);
  24. Readln;
  25. except
  26. on E: Exception do
  27. Writeln(E.ClassName, ': ', E.Message);
  28. end;
  29.  
  30. end.

Codigo asm generado (hasta la ejecucion de la rutina Writeln)
 

delphi
  1. Project2.dpr.28: Valor(S);
  2. 004101BB A16C6E4100 mov eax,[$00416e6c]
  3. 004101C0 E827E2FFFF call Valor
  4.  
  5. Valor
  6. 0040E3EC 55 push ebp
  7. 0040E3ED 8BEC mov ebp,esp
  8. 0040E3EF 51 push ecx
  9. 0040E3F0 8945FC mov [ebp-$04],eax
  10. 0040E3F3 8B45FC mov eax,[ebp-$04]
  11. 0040E3F6 E8A17CFFFF call @UStrAddRef
  12. 0040E3FB 33C0 xor eax,eax
  13. 0040E3FD 55 push ebp
  14. 0040E3FE 6836E44000 push $0040e436
  15. 0040E403 64FF30 push dword ptr fs:[eax]
  16. 0040E406 648920 mov fs:[eax],esp
  17. Project2.dpr.10: Writeln(S);
  18. 0040E409 A1CC1C4100 mov eax,[$00411ccc]
  19.  
  20. Project2.dpr.29: Referencia(S);
  21. 004101C5 B86C6E4100 mov eax,$00416e6c
  22. 004101CA E871E2FFFF call Referencia
  23.  
  24. Referencia
  25. 0040E440 53 push ebx
  26. 0040E441 8BD8 mov ebx,eax
  27. Project2.dpr.15: Writeln(S);
  28.  
  29. Project2.dpr.30: Constante(S);
  30. 004101CF A16C6E4100 mov eax,[$00416e6c]
  31. 004101D4 E883E2FFFF call Constante
  32.  
  33. Constante
  34. Project2.dpr.19: begin
  35. 0040E45C 53 push ebx
  36. 0040E45D 8BD8 mov ebx,eax
  37. Project2.dpr.20: Writeln(S);

En este caso el codigo ASM generado tanto para var como para const es igual (excepto el pasaje del parametro); la unica diferencia es que el string const obviamente no puede ser modificado, mientras que el var si
 
Por otra parte, el pasaje por Valor en este caso tomo muchas mas operaciones, me imagino que porque tuvo que crear un string en ese momento
 
Saludos
  • 3




IP.Board spam blocked by CleanTalk.