quinta-feira, 13 de agosto de 2009

Carregando variáves de arquivo LUA

Olá, depois de um tempo sem postar nada, trago um exemplo de como se carregar variáveis de um arquivo lua para o seu aplicativo em c++, utilizando Dev-C++.

A linguagem lua vem sendo utilizada em muitos jogos, um grande exemplo é o jogo online Tibia, não é grande a atuação da linguagem lua neste jogo, ela é utilizada para se carregar variáveis como SERVIDOR, USUARIO, VERSÃO, entre outros detalhes.

Então vamos lá. Primeiramente temos que entender que a biblioteca que utilizaremos para carregar arquivos lua foi inicialmente desenvolvida para C, portanto, se você pretende utilizar C++ é necessário um comando para que seja possivel utilizar.

externn "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

Agora vamos ao nosso arquivo lua que guardará as variáveis. Crie um arquivo com a extenção lua e grave as seguintes vareiáveis:

SERVIDOR = "localhost"
USUARIO = "ROOT"
SENHA = "123"


Salve-o com o nome que desejar, desde que esteja na mesma pasta que o seu projeto. Para que o nosso programa possa ler as variáveis quando quiser, sem necessitar de um código enorme toda a vez que for capturar a variável, vamos criar uma função CarregaVariavel do tipo Const Char*. Esta função recebera o seguinte parâmetro:
variavel é a variavel que será carregada.
const char* CarregaVariavel(char* variavel)
{
// Variavel
lua_State *LuaVar = lua_open();
// Carrega o arquivo
int sts = luaL_loadfile(LuaVar, "hello.lua");

// Se carregou o arquivo
if( sts== 0 ) {
// Carrega os dados do arquivo em si...
sts = lua_pcall(LuaVar, 0, LUA_MULTRET,0);
}

// Captura o valor da variavel entre aspas.
lua_getglobal(LuaVar,variavel);
// Atribui a uma variavel o valor capturado
return lua_tostring(LuaVar,-1);

lua_close(LuaVar);
}

Para chamarmos a nossa função, declararemos uma variavel do tipo const char e chamamos a nossa função. como abaixo
const char *teste;
teste = CarregaVariavel(
"SERVIDOR");

O nosso programa final pode ser visto na listagem abaixo.

const char* CarregaVariavel(char* variavel);

int main( int argc, char ** argv) {

const char *servidor;
const char *usuario;
const char *senha;

servidor = CarregaVariavel( "SERVIDOR" );
cout << servidor << endl;
usuario = CarregaVariavel("USUARIO");
cout << usuario << endl;

senha = CarregaVariavel("SENHA");
cout << senha << endl;
system("pause");
return 0;
}

const char* CarregaVariavel(char* variavel)
{
// Variavel
lua_State *LuaVar = lua_open();
// Carrega o arquivo
int sts = luaL_loadfile(LuaVar, "hello.lua");

// Se carregou o arquivo
if( sts== 0 ) {
// Carrega os dados do arquivo em si...
sts = lua_pcall(LuaVar, 0, LUA_MULTRET,0);
}

// Captura o valor da variavel entre aspas.
lua_getglobal(LuaVar,variavel);
// Atribui a uma variavel o valor capturado
return lua_tostring(LuaVar,-1);

lua_close(LuaVar);
}

"Mas pô sipmann.. deu erro na hora de compila aqui no dev...??"... Para poder compilar é necessário baixar o pacote (através do sistema de pacotes do dev mesmo) "lua"... "Prontooo... e agora???"... Agora é necessário dizer ao compilador que iremos utilizar a biblioteca que acabamos de baixar (lembram do acesso ao mysql??? mesma coisa) Project >> Project Options >> Parameters... ai na lista "Linker" adicionem as duas linhas a seguir...
-lLua -lLualib

Pronto... só compilar e brincar...
Abração e espero que tenham gostado... qualquer duvida só posta ai... até

sexta-feira, 12 de junho de 2009

Revista programar: Metaprogramação em C++

A revista Programar dos nossos irmãos lusitanos em sua edição 20 publicou um interessante artigo sobre Metaprogramação em c++.


Fica assim nossa recomendação de leitura para o fim de semana: http://www.revista-programar.info/front/view/26

Aufwiederzehn!

domingo, 31 de maio de 2009

Otimizações do compilador GCC

Olá pessoal, esse pequeno post é para falar sobre compilação com otimização do compilador. Para isso vamos medir o tempo de execução de nosso programa.

Usei o exemplo do post anterior, de qualquer forma segue o código abaixo:
#include 
#include

double tempo()
{
struct timeval tv;
gettimeofday(&tv,0);
return tv.tv_sec + tv.tv_usec/1e6;
}

int main()
{
double t1,t2;
double i;
t1 = tempo();
printf("%lf\t",t1);

for(i=0;i<300000000;i++);

t2 = tempo();
printf("%lf\t",t2);

printf("%lf\n",t2-t1);
return 0;
}

Na hora de compilar um programa com o GCC você pode colocar alguns parâmetros, vamos usar:

-O1 Otimiza para tamanho do binário
-O2 Otimiza para desempenho de execução
-O3 Otimiza para Data cache

* Atenção é "O" (letra) e não "0" (número).

Vamos aos testes:

[helton2@hrpc ~]$ gcc teste.c -O1
[helton2@hrpc ~]$ ./a.out
1243797632.612002 1243797633.767017 1.155015

Neste exemplo o tamanho do binário ficou em 6329 bytes e demorou 1.155 segundos.


[helton2@hrpc ~]$ gcc teste.c -O2
[helton2@hrpc ~]$ ./a.out
1243797643.222072 1243797644.371347 1.149275

Neste exemplo o tamanho do binário ficou em 6345 bytes e demorou 1.149 segundos.

[helton2@hrpc ~]$ gcc teste.c -O3
[helton2@hrpc ~]$ ./a.out
1243797650.764788 1243797651.959029 1.194241

Neste exemplo o tamanho do binário ficou em 6409 bytes e demorou 1.194 segundos.

Compilando da forma padrão ...

[helton2@hrpc ~]$ gcc teste.c
[helton2@hrpc ~]$ ./a.out
1243797667.095339 1243797670.080635 2.985296

Neste exemplo o tamanho do binário ficou em 6369 bytes e demorou 2.985 segundos.

Como aqui estamos tratando de um problema fácil, apenas um simples "for" a diferença é pequena, mas com problemas mais complexos, sem dúvida essas opções de compilação podem dar um "up" no seu programa.

As opções aqui abordadas são válidas para a maioria dos compiladores C e C++ tanto em ambiente unix, linux, mac e windows.

Dica de Claudio Schepke. Obrigado!

quinta-feira, 14 de maio de 2009

Como instalar o GCC em Mandriva pela linha de comando?

Vamos ver aqui simples rápido como instalar programas (aqui vamos instalar o GCC, mas serve para qualquer outro) em distribuição Mandriva (qualquer versão) ou outra distribuição que utiliza o gerenciador de pacotes URPMI.

O URPMI é como o APT das distribuições baseadas em Debian... um gerenciador de pacotes.

Bom, o primeiro passo é "testar" se a instalação de um dado pacote (rpm, que está nos repositórios) é possível. Para isso (com root) usamos "urpmi -- test gcc", onde "gcc" é o pacote que queremos instalar.
O URPMI então nos diz se é possíovel ou não. Para instalar então tem que dar o comando "urpmi gcc" onde gcc é o pacote que queremos instalar.


No início da tela anterior, executamos o comando "gcc" e como pode ver, não havia esse comando, instalamos, executamos novamente e tudo ok.

É essa a dica, agora você que usa uma máquina rodando alguma distribuição que usa RMPI, e acessa ela remotamente por SSH por exemplo e que não tem acesso a interface gráfica... já pode programar em C.

Welcome to jungle :)
Bye

sábado, 25 de abril de 2009

Fatorial Recursivo em C

Neste pequeno tutorial vou demonstrar o cálculo do fatorial utilizando recursividade na linguagem C. O fatorial de um número é igual a ele mesmo vezes ele menos um até chegar em um, exemplo:

Fatorial de 4 é igual a 4*3*2*1 que é igual a 24.
Fatorial de 5 é igual a 5*4*3*2*1 que é igual a 120.

Na função a seguir temos cálculo do fatorial de um número sem usar recursividade. Ela recebe como parâmetro um número inteiro e retorna o fatorial daquele número.


int fatorial (int n)
{
int i;
i = n - 1;
for (i; i!=1; i--)
n = n * i;
return n;
}

Então podemos considerar que:

- o fatorial de 5 é igual a 5 multiplicado pelo fatorial de 4;
- o fatorial de 4 é igual a 4 multiplicado pelo fatorial de 3;
- o fatorial de 3 é igual a 3 multiplicado pelo fatorial de 2 e assim por diante.

Montando uma função matemática temos:


fatorial de x = x * fatorial de ( x -1 );


Entendido isso, a nossa função recursiva está praticamente pronta, basta adicionar uma condição de fim, que na função anterior é i diferente de 1. Veja a seguir a implementação da função em C.


int fatorial (int n)
{
if(n==1)
return n;
return fatorial(n-1) * n;
}

Simples assim, até.

domingo, 19 de abril de 2009

Qual o tempo de execução de meu aplicativo?

Há situações em que precisamos medir quanto tempo demorou a execução de um determinado procedimento, ou a execução de um programa. Neste caso no Linux podemos usar a função gettimeofday().

Para mais detalhes... na linha de comando digite: man gettimeofday

Algumas informações úteis:

- a função retorna um int
- o primeiro parâmetro é a struct timeval (arquivo time.h), e o segundo é um valor de timezone, mas esse parametro está deprecated, e como diz na documentação costuma-se usar um valor nullo (0, zero)
- para que isso funcione você precisa ter no seu computador a glibc.

Vamos ao código e posterior análise:
#include <stdio.h>
#include <stdlib.h>

double tempo()
{
struct timeval tv;
gettimeofday(&tv,0);
return tv.tv_sec + tv.tv_usec/1e6;
}

int main()
{
double t1,t2;
double i;
t1 = tempo();
printf("%lf\t",t1);

for(i=0;i<300000000;i++);

t2 = tempo();
printf("%lf\t",t2);

printf("%lf\n",t2-t1);
return 0;
}



1 - Criamos uma função que retorna um double, a função tempo()
double tempo()
{
struct timeval tv;
gettimeofday(&tv,0);

return tv.tv_sec + tv.tv_usec/1e6;
}

Essa função declara uma variável chamada tv, que é do tipo da struct timeval (lembre... essa struct está definida no arquivo time.h). Depois chamamos a função propriamente, passando um ponteiro para nossa variável tv e o segundo parâmetro como a documentação sugere com valor nulo.

Depois dividimos os microsegundos por 1000000 para convertê-los em segundos (deixe 1e6, não sei porque, mas se dividir por 1000000 não vai dar certo ... isso ainda é um mistério), somamos a esse resultado os os segundos de agora. A struct timeval tem dois atributos, tv_sec (os segundos de agora) e tv_usec (os microsegundos do segundo de agora). Como nossa variável se chama tv, então para acessar os microsegundos usamos tv.tv_usec.

Agora o main de nosso programa:

int main()
{
double t1,t2;
double i;
t1 = tempo();
printf("%lf\t",t1);

for(i=0;i<300000000;i++);

t2 = tempo();
printf("%lf\t",t2);

printf("%lf\n",t2-t1);
return 0;
}

Declaramos t1 e t2 do tipo double (a máscara para double é %lf lembra?) e também um i que vai ser nosso contador.

Queremos medir quanto tempo demorou um for de 0 até 300000000 (300 milhões), por isso guardamos o tempo de agora em t1 e depois do for em t2, mostramos isso na tela (já vai ver porque). Diminuimos t1 de t2 e temos em segundos quanto que demorou nosso bloco de códigos.

Compilando ...
gcc teste.c
mv a.out teste

Compilei (gerou o a.out) e renomeei isso para teste.

Executando:
./teste

Vai produzir um resultado como:
1240195429.991010 1240195432.975001 2.983991

Temos o tempo inicial, tempo final e a diferença. Atenção!! Se você tiver um computador lento é aconselhavel diminuir o tamanho do for ... a não ser que tenha paciência.

Estou rodando o programa num computador:
uname -a
Linux hrpc 2.6.27.14 # i686 Intel(R) Pentium(R) 4 CPU 3.00GHz GNU/Linux

Legal!! Descobrimos que demorou 2.98 segundos ... mas pense bem, foi a primeira vez que eu executei o programa na máquina ... será que nas vezes seguintes vai ser diferente o tempo? Talvez o programa já vai estar carregado na memória? E ... fora o programa eu tenho mais vários outros processos executando em meu computador... será que eles não interferem?

Só tem uma maneira de saber... rodando mais vezes o programa e vendo o tempo que resultou...

Segue abaixo um shell script que faz o programa executar 50 vezes e guarda (acumulando) o valor dos printf em um arquivo. Atenção para o caminho dos arquivos aí na sua máquina.
#!/bin/sh
i=1
while [ $i -le 50 ]
do
/home/helton2/teste >> /home/helton2/resultados.txt
i=`expr $i + 1`
done

exit 0

Este código aí acima é do arquivo runteste.sh, criamos esse arquivo e damos permissão de execução a ele (chmod +x runteste.sh), aí ele é um executável igual nosso programa em C.

Para rodá-lo então:
./runteste.sh

Isso vai criar em "/home/helton2/" o arquivo "resultados.txt" com valores semelhantes (depende de em que dia você está executando e quão rápida é sua máquina) aos listado abaixo:

1240195429.991010 1240195432.975001 2.983991
1240195432.980598 1240195436.225005 3.244407
1240195436.230919 1240195439.232810 3.001891
1240195439.238001 1240195442.226818 2.988817
1240195442.231239 1240195445.222347 2.991108
1240195445.228246 1240195448.210298 2.982052
1240195448.216515 1240195451.466147 3.249632
1240195451.472111 1240195454.732387 3.260276
1240195454.738784 1240195457.728088 2.989304
1240195457.734230 1240195460.976687 3.242457
1240195460.981184 1240195464.242882 3.261698
1240195464.247674 1240195467.239435 2.991761
1240195467.245351 1240195470.236075 2.990724
1240195470.241656 1240195473.518475 3.276819
1240195473.522821 1240195476.506720 2.983899
1240195476.511950 1240195479.494113 2.982163
1240195479.499256 1240195482.492852 2.993596
1240195482.497447 1240195485.473576 2.976129
1240195485.478231 1240195488.463446 2.985215
1240195488.471239 1240195491.746600 3.275361
1240195491.752356 1240195494.763777 3.011421
1240195494.768697 1240195498.037331 3.268634
1240195498.041838 1240195501.072781 3.030943
1240195501.077732 1240195504.334191 3.256459
1240195504.340106 1240195507.636492 3.296386
1240195507.641648 1240195510.639141 2.997493
1240195510.644422 1240195513.607822 2.963400
1240195513.613151 1240195516.608085 2.994934
1240195516.613102 1240195519.872248 3.259146
1240195519.877602 1240195523.154833 3.277231
1240195523.162235 1240195526.428517 3.266282
1240195526.433406 1240195529.866800 3.433394
1240195529.879949 1240195533.494374 3.614425
1240195533.499518 1240195536.512687 3.013169
1240195536.517868 1240195539.777852 3.259984
1240195539.784743 1240195543.055148 3.270405
1240195543.060538 1240195546.337556 3.277018
1240195546.343325 1240195549.587118 3.243793
1240195549.591585 1240195552.838038 3.246453
1240195552.844843 1240195556.124090 3.279247
1240195556.129737 1240195559.367544 3.237807
1240195559.375004 1240195562.423662 3.048658
1240195562.428425 1240195565.675685 3.247260
1240195565.680207 1240195568.961254 3.281047
1240195568.966475 1240195572.196674 3.230199
1240195572.202217 1240195575.433472 3.231255
1240195575.454523 1240195578.449320 2.994797
1240195578.454862 1240195581.466028 3.011166
1240195581.471327 1240195584.739090 3.267763
1240195584.744280 1240195587.976532 3.232252

Agora sim temos dados um pouco melhores!!! Copie-os na sua planilha de cálculos preferida e jogue com os dados!!!!

Aqui achei algumas coisas:

melhor tempo: 2,9634000
pior tempo: 3,6144250
tempo médio: 3,1538744
Maior diferença de tempo : 0,6510250

Sem contar que daria para fazer um belo gráfico de dispersão com esses dados!

Valeu pessoal!!

Planejo fazer meu próximo post sobre structs.

Agradescimentos a Claudio Schepke pela dica da função gettimeofday