# Strings

2009-07-07 tag_coding ^

Como já vimos centenas e centenas de vezes, memória é apenas memória até que alguém diga que isso vale alguma coisa. Em seu estado latente é o que chamamos formalmente de dados. E dados são bytes armazenados na memória.

No entanto, quando esses dados viram algo de útil em um determinado contexto, não necessariamente alterando-se seu conteúdo na memória, passamos a lidar com informação. Ou seja, é um dado com significado. E informação é a interpretação desses mesmos dados.

A conclusão óbvia para isso, falando de strings, é: uma série de bytes enfileirados na memória pode ser uma string.

Para tanto precisamos apenas de dados (os bytes enfileirados) e significado (uma tabela de símbolos que traduza esses bytes para caracteres e a definição de como a string se organiza).

Por exemplo, uma série de bytes diferentes de zero com valores que representam índices de uma tabela de tradução de caracteres e que termina sua sequência em um byte com o valor zero nele é considerada uma string C, ou string terminada em nulo.

Já uma mesma sequência de bytes no mesmo molde só que sem o byte final com o valor zero, mas com um byte inicial que tem como valor não um índice de caractere, mas o número de bytes subsequentes, isso é uma string Pascal, ou uma string com contador de tamanho.

Agora note por que tanto uma string vazia em Pascal e em C possuem os mesmos dados, mas informação diferente.

Outras strings que não necessariamente possuem terminador nulo: std::string, UNICODESTRING.aspx), strings no kernel.


# Polimorfismo estático

2009-07-10 tag_coding ^

Para explicar polimorfismo, nada como ver as coisas como elas eram. Se você fosse um programador C de vinte anos atrás e criasse as seguintes funções:

int soma(int x, int y);
double soma(double x, double y);
int main()
{
    int zi = soma(2, 3);
    double zd = soma(2.5, 3.4);
    return 0;
}

Imediatamente o compilador iria acusar os seguintes erros:

   overload.c
   
   overload.c(2) : warning C4028: formal parameter 1 different from declaration
   overload.c(2) : warning C4028: formal parameter 2 different from declaration
   overload.c(2) : error C2371: 'soma' : redefinition; different basic types
           overload.c(1) : see declaration of 'soma'

Isso acontece porque em C **os identificadores são únicos por escopo**. Esse é o motivo por que o seguinte código também está errado:

int main()
{
    int x = 0;
    int x = 1;
    return 0;
}
   overload.c
   overload.c(5) : error C2374: 'x' : redefinition; multiple initialization
           overload.c(4) : see declaration of 'x'

De volta aos anos 90, isso também está errado em C++. Até por uma questão de lógica: como o compilador pode saber a qual variável estamos nos referindo se usarmos o mesmo nome para duas delas?

Só que existe um truquezinho para impedir essa ambiguidade quando falamos de funções: os parâmetros que ela recebe.

int soma(int x, int y);
double soma(double x, double y);
int main()
{
    int zi = soma(2, 3); // dois tipos int: chamar soma(int, int)
    double zd = soma(2.5, 3.4); // dois tipos double: só pode ser soma(double, double)
    return 0;
}
   C:\Tests>cl /c overload.cpp
   Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.6030 for 80x86
   Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
   
   overload.cpp
   
   C:\Tests>

Isso permitiu que em C++ fosse criada a sobrecarga estática, que é exatamente isso: chamar a função não apenas de acordo com seu nome, mas também de acordo com sua assinatura, ou seja, o número e o tipo dos parâmetros recebidos. Chamamos de sobrecarga estática porque isso é feito apenas pelo compilador, não pesando em nada durante a execução do programa.

Entre seus usos mais comuns estão os seguintes:

 * Ter funções com o mesmo nome mas que tratam de diferentes parâmetros;
   * soma(int, int);
   * soma(double, double);
   * Obs.: Isso ignora, é claro, as facilidades dos templates.
 * Versões novas da mesma função que recebem parâmetros adicionais;
   * export_data(void* buffer, int size);
   * export_data(void* buffer, int size, unsigned long options);
 * Mesmo nome de método para setar e obter o valor de uma propriedade;
   * Class::Property(int x); // setter
   * int x Class::Property() const; // getter
 * Bom, o que mais sua imaginação mandar =)

# Static Polymorphism

2009-07-10 tag_coding tag_english ^

To explain the polymorphism nothing is better than see how stuff used to be. If you were a twenty old C programmer in the past and created the following functions:

int soma(int x, int y);
double soma(double x, double y);
int main()
{
    int zi = soma(2, 3);
    double zd = soma(2.5, 3.4);
    return 0;
}

Immediately the compiler would blame you about the following errors:

   
   overload.c
   
   overload.c(2) : warning C4028: formal parameter 1 different from declaration
   overload.c(2) : warning C4028: formal parameter 2 different from declaration
   overload.c(2) : error C2371: 'sum' : redefinition; different basic types
           overload.c(1) : see declaration of 'sum'

This happens because in C **the identifiers are unique into the scope.** This is the reason why the following code is wrong also:

int main()
{
    int x = 0;
    int x = 1;
    return 0;
}
   overload.c
   overload.c(5) : error C2374: 'x' : redefinition; multiple initialization
           overload.c(4) : see declaration of 'x'

Back to the 90's, this is also wrong in C++. Even for a logic issue: how the compiler can pick a variable if we're using the same name for both of them?

Even though, there's a little trick to stop the ambiguity when we talk about functions: the parameters that they receives.

int soma(int x, int y);
double soma(double x, double y);
int main()
{
    int zi = soma(2, 3); // dois tipos int: chamar soma(int, int)
    double zd = soma(2.5, 3.4); // dois tipos double: só pode ser soma(double, double)
    return 0;
}
   C:Tests>cl /c overload.cpp
   Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.6030 for 80x86
   Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
   
   overload.cpp
   
   C:Tests>

This allowed in C++ the creation of static overload, that is exactly this: to call a function not just by its name, but also to match its signature, the number and the type of the received parameters. We call static because this is done just by the compiler, not creating any overhead during the execution.

Among the most common uses some are as it follows:

 * Functions with the same name treating different parameters;
   * sum(int, int);
   * sum(double, double);
   * Obs.: This ignores, of course, the templates usefulness.
 * New version of the same fuction with addictional parameters;
   * export_data(void* buffer, int size);
   * export_data(void* buffer, int size, unsigned long options);
 * Same method name to set and get the value of a class property;
   * Class::Property(int x); // setter
   * int x Class::Property() const; // getter
 * Well, whatever your imagination and needs demand =)

# Name mangling

2009-07-13 tag_coding ^

A sobrecarga estática possui algumas desvantagens em relação ao sistema de nomes da boa e velha linguagem C: ela não foi padronizada entre compiladores. O que isso quer dizer na prática é que funções exportadas de bibliotecas dinâmicas (DLLs) vão possuir nomes diferentes dependendo do compilador utilizado (e sua versão). Isso é o que chamamos name mangling.

Em dois projetos usando Visual C++ 2008 e Borland C++ Builder 5 (última versão que funciona direito) eu fiz uma exportação da função soma em linguagem C (o fonte é um .c). Veja o resultado:

Já usando a linguagem C++ (o fonte é um .cpp) temos outro resultado totalmente diferente para nossas duas funções soma descritas no artigo anterior:

Se quiser tentar entender essas letrinhas bizarras, recomendo baixar projetos de exemplo. Se apenas entender que você não conseguirá juntar classes VC++ e Builder usando dllexport.aspx) para tudo quanto é lado, então terminamos por aqui.


# À procura de vida extraterrestre

2009-07-20 ^

Faz uns bons dez anos que eu instalei pela primeira vez em meu Pentium 133 MHz o seti@home, um programinha que se propunha a localizar vida extraterrena através de emissões de rádio capturadas pelas nossas potentes antenas de Arecibo. Ele dizia fazer isso durante o tempo ocioso do meu processador. Como eu sou uma pessoa que costuma costumava confiar bastante nas pessoas, além de ser fã incondicional do filme Contato, instalei sem medo.

Algum tempo se passou e hoje volto a instalar o mesmo programa, agora envolto em um invólucro de programas de mesmo teor chamado Boinc, que junta todas essas redes de trabalho em equipe. O computador é usado hoje em dia para diversos trabalhos que exigem um certo esforço no processamento que torna proibitivo alocar máquinas somente para isso (se não impossível do ponto de vista geográfico).

Eis uma lista dos principais projetos disponíveis através do Boinc que me chamaram a atenção:

  • Climateprediction.net busca prever as possíveis consequências para o mundo das futuras transformações no clima.
  • CPUGrid.net é uma simulação molecular de proteínas otimizada para as GPUs da NVidia e o Playstation 3.
  • Superlink@Technion e ajude os cientistas a encontrar os prováveis genes causadores de fatalidades como câncer, a diabetes, hipertensão e esquizofrenia.
  • Chess960@home para análise de uma variante do xadrez tradicional que sempre coloca as peças iniciais em posições aleatórias.
  • PrimeGrid é um gerador de uma base de dados pública de números primos sequenciais, além de procurar por números primos gêmeos gigantes (vai saber).
  • Quantum Monte Carlo at Home não é o que parece: Estudo da estrutura e da reatividade de moléculas usando a Química Quântica (?).

Dentre eles, acabei ficando mesmo com o bom e velho seti@home. Pode me chamar de egoísta, mas mesmo que encontrem a cura do câncer, não será muito produtivo para mim, que possuo questões existenciais que, acredito eu, facilitariam a compreensão das pessoas acerca da nossa extrema pequenez nesse universo, nos colocando cada vez mais no cantinho de nossa existência.

Escolha o seu!


# Cuidado com a cópia de arquivos na VMWare

2009-07-27 ^

Quebrei a cabeça com uma DLL de hook que não estava funcionando para usuários comuns. No entanto, para qualquer administrador funcionava.

Isso acontece porque quando se arrasta uma DLL recém-compilada para a VMWare ela possui um mecanismo que primeiro cria esse arquivo no temporário do usuário atual e depois move esse arquivo para o lugar onde você de fato arrastou.

Como sabemos, a pasta temporária de um usuário fica em seu perfil, que possui direitos de uso apenas do usuário e dos administradores do sistema. Se eu copio um arquivo de uma pasta restrita para outra pasta os direitos do arquivo permanecem. Isso quer dizer que apenas o usuário atual e os administradores terão acesso ao arquivo, mesmo que se trate de um arquivo para uso de todos.

Resultado: arrastava a nova DLL de hook compilada da pasta de saída direto para a pasta de sistema da máquina virtual e esse caminho através do temporário era seguido, tornando a DLL inacessível para os usuários que eu estava testando.

Solução: após arrastar o arquivo, mude suas permissões. Ou copie-o através do bom e velho copiar/colar. Diferente do arrastar, o Ctrl+C Ctrl+V não gera arquivos temporários.


<< >>