Pesquisar
quarta-feira, 16 de dezembro de 2020
Os Segredos de TStringList - Parte 2
quinta-feira, 12 de novembro de 2020
Strings no Delphi
Ao longo da vida do Delphi, em todas a idas e vindas, Borland, Code Gear e Embarcadero, o Delphi já utilizou alguns tipos de strings, vamos explorar brevemente esses tipos.
Delphi 1 - String é um alias para ShortString (tamanho máximo de até 255);
Delphi 2 até Delphi 2007 - String é um alias para AnsiString (tamanho máximo de até 2Gb);
Delphi 2009 até hoje - String é um alias para UnicodeString (virtualmente sem tamanho, porem, por causa da codificação ocupa o dobro do tamanho);
Todas estas variantes de strings ainda estão disponíveis no Delphi 10.4 e podem ser utilizada.
Diferença básica entre os tipos:
ShortString
Nada mais é do que um ponteiro de caracteres, herdado do turbo pascal (Borland), o compilador pré aloca 256 caracteres para este tipo de dados, mesmo que seja utilizado menos que isso. Ou seja, sempre é ocupado 256 bytes;
É possível especificar o tamanho máximo para estas strings, porem esse valor não pode ultrapassar 255;
Ex:
var
lTemp1: string[50]; //Pré aloca 51 bytes, 50 para utilização e 1 byte de controle.
lTemp2: string[256]; //Erro, o tamanho máximo é de 255 mais 1 de controle, então a declaração de uma shortstring de 256 bytes não é possível.
lTemp3: shortstring; //Pré aloca 256 bytes, 255 para utilização e 1 de controle.
Toda a estrutura de dados do tipo ShortString é armazenado na memória stack, tornado a velocidade de acesso a esse tipo de estrutura extremamente rápido, porem com a atual velocidade dos processadores e acesso a memória, esta velocidade simplesmente não é percebido até mesmo por computadores mais antigos. No entanto, se vc for utilizar alguma estrutura de dados em que seja necessário repetir algumas milhares de vezes uma string, talvez valha a pena avaliar a utilização deste tipo;
AnsiString (Também conhecida como Long String)
Na versão 2 do Delphi, a Borland introduziu a AnsiString, um tipo melhorado de ShortString, mas com algumas diferenças significativas.
Agora era possível utilizar strings com o tamanho de até 2Gb de tamanho. Além disso, o Delphi agora era capaz de alocar uma quantidade de memória mais condizente com sua utilização. A alocação dinâmica era possível com este tipo de dado que utilizava um NULL TERMINATOR para identificar o final da string e não apenas um payload de tamanho no início da estrutura de dados.
Foi introduzido tb um contador de referencia, para que strings iguais não se repetissem. Tornado assim o AnsiString um tipo de dado extremamente versátil de ser utilizado.
Ex:
var
lTemp1: AnsiString;
lTemp2: AnsiString;
begin
lTemp1:= 'Teste';
lTemp2:= lTemp1; //Neste momento, o contador de referencia para a string é incrementado e a string não é copiáda, mas referenciada em lTemp2;
//Caso o valor das string 'Teste' seja alterado em qualquer uma das variáveis, o compilador realiza uma cópia da mesma e o contador de referencia será decrementado, isso de forma totalmente transparente ao programador.
end;
Por muito tempo esta foi a utilização padrão do delphi, e muitas DLLs foram criadas com este padrão de string.
O ponteiro de uma string local sempre aponta para a memória de acesso rápido (stack), mas o conteúdo da string, geralmente aponta para a memória mais lenta, a heap.
WideString
Este tipo de dado é muito semelhante a AnsiString, porem foi criado para manter a compatibilidade com funções que era utilizada com Windows 64.
Ele se comporta do mesmo modo que o AnsiString, no entanto os caracteres são unicode, ocupando o dobro do tamanho de espaço.
UnicodeString
É o tipo padrão de string utilizado pelo Delphi desde a sua versão 2009. Para todos os efeitos funciona como a AnsiString, mas sem a limitação dos 2Gb e ainda é unicode. Geralmente utiliza a codificação UTF-16, mas pode ser configurada para utilizar a codificação UTF-8.
A alteração do tipo string de AnsiString para UnicodeString ocasionou um rebuliço na comunidade, pois várias bibliotecas deixaram de manter a compatibilidade. O melhor exemplo disso é a carga de DLL que utilizava o padrão AnsiString (DLLs criadas em Delphi 7 em sua maioria) em versão mais novas do Delphi (2009 e superior). Claro que a solução era a tipagem correta na chamada dessas DLLs, mas como isso nunca havia ocorrido, muito poucos programadores tiveram essa visão.
Resumo
AnsiString: string composta por caracteres ASCII. Cada Char possui exatamente 1 bytes. Um ponteiro para uma AnsiString (^AnsiString) equivale a char* em C;
WideString: existe apenas por compatibilidade com o Windows. Cada Char possui 2 bytes, e deve ser utilizada em funções da Win32 com parâmetros LPWSTR, realizando um cast para PWChar;
UnicodeString: string unicode. Por padrão UTF-16 (ou pelo menos era quando pesquisei pela última vez), mas pode assumir outras codificações, como UTF-8.
ShortString: equivale a string antiga do Pascal, com sua limitação de de 255 caracteres.
String: nas versões mais novas do Delphi (2009 em diante), equivale a UnicodeString. Antigamente equivalia a AnsiString.
Tanto AnsiString quanto UnicodeString são mais do que um simples "array of Char", sendo que elas possuem informações de página de código e tamanho. Porém, para facilitar o cast destes tipos para PChar e suas variações, estas informações ficam nos endereços anteriores ao retornado pelo operador @.
Conversão
A conversão entre elas é feita automaticamente. Único cuidado que deve ser tomado, é que dados podem ser perdidos durante a conversão devido ao tipo não suportar alguma característica da string de origem, gerando assim um "Warning" no compilador.
O compilador ainda pode fazer um cast implícito para o tipo adequado, mas isso também gera um "Warning" no compilador.
Por exemplo, converter UnicodeString para AnsiString, pode haver perda devido aos caracteres Unicode poderem ocupar mais que 1 byte.
Conversão de AnsiString (ou UnicodeString) para ShortString, haverá perda de dados se a string de origem for maior que 255 (Length(origem) > 255).
Conclusão
Não sou um especialista em strings de Delphi, e tentei explicar brevemente como o mecanismo de escrita de strings funciona. Por óbvio que existe muito mais coisa por traz de um tipo complexo como a strings, mas espero ter ajudado minimanete o leitor a resolver possíveis problemas de compatibilidade que podem aparecer na vida do developer.
domingo, 14 de junho de 2020
Criação de Logs em aplicações Delphi e um pouco sobre Seções Crítica (TCriticalSection)
var
lFileLogName: string;
lFile: TextFile;
begin
//Entrado na seção cítica
TFileTextLog.FCriticalSection.Enter;
try //Bloco protegido
//Definindo o nome do arquivo que sera gravado, sempre atribuo o arquivo de log
// o mesmo nome do EXE só que com a extensão LOG
lFileLogName:= ChangeFileExt(ParamStr(0), '.log');
//Vinculo a variável lFile ao nome do arquivo, basicamente eu obtenho um ID (handle)
// do SO para este arquivo
AssignFile(lFile, lFileLogName);
//Crio outro bloco protegido para fazer a liberação do arquivo para o SO
try
//Verifico se o arquivo ja existe
if not FileExists(lFileLogName) then
Rewrite(lFile) //Se não existe, então cria e abre o arquivo para edição
else
Append(lFile); //Senão apenas abro o arquivo que ja existe para edução
//Simplesmente escrevo a linha desejada no final do arquivo
WriteLn(lFile, FormatDateTime('dd/mm/yyyy hh:mm:ss:zzz', Now) + ' => ' + lText);
finally
//Fecho o aquivo, informo ao SO que não sera mais utilizado (desbloqueio ele)
CloseFile(lFile);
end;
finally
//Libero a seção crítica
TFileTextLog.FCriticalSection.Release;
end;
end;
sábado, 13 de junho de 2020
Repositório de Exemplos Delphi
Depois de quase 5 anos da minha última postagem, estou aqui para informar que estou montando um repositório no GitHub de exemplos que eu realmente acho útil...
Desejo pelo menos criar exemplos mensais, os exemplos são bem práticos e objetivos.
Ja deixei la o primeiro exemplo, onde crio threads e criação de logs em arquivo texto.
Em breve devo escrever uma postagem explicando o exemplo.
Abraço a todos!
Meu repositório de exemplos:
https://github.com/maicodalri/delphi_samples
Canal da Aquasoft no YouTube:
https://www.youtube.com/channel/UCwrdLw9wVt3ls9WCgy5Bc2A