quarta-feira, 22 de agosto de 2018

C: Imprimindo percentual

É muito comum uma saída com percentual, e com o símbolo '%' depois do número, mas a printf() usa este caractere para formatação de saída. Qual é a solução?

Já vi muitas vezes sendo resolvido assim:

printf( "%f %s\n",pecent,"%" );

Isto está errado, realmente muito errado. Mas por que está errado, e qual é a solução?

C: Ponteiros para função

Em C existe um recurso muito incomum. Ponteiros para funções. Não sei de outra linguagem que tenha isto, além de C e C++. Não sei se outras linguagens derivadas do C, como Java e C# tem isto (Podem responder nos comentários). Dá para fazer em Assembly, mas isto não conta.

Qual é o uso disto? Depende do caso. É possível passar uma função, aliás, o endereço de uma função, como parâmetro para outra função, para que ela a chame dentro dela, por exemplo.

Então vamos a um exemplo prático:

terça-feira, 17 de abril de 2018

Testando os quadrados por somas de ímpares de Pitágoras e otimização

Eu vi a seguinte publicação no Facebook e pensei em testar computacionalmente até um limite grande. Para quem não quer, ou não tem como, acessar o Facebook, reproduzo a imagem abaixo:


Quando escrevia o programa notei que estava fazendo errado, que o código iria gastar tempo demais inutilmente, então reescrevi o código resolvendo isto.

A primeira versão do programa foi:

#include        <stdio.h>

int     main()
{
        register unsigned long long numero, impar, soma ;

        for( numero = 1 ; numero <= 1000000000 ; numero++ )
        {
                register int    i ;

                for( i = numero, impar = 1, soma = 0 ; i ; i--, impar +=2 )
                        soma += impar ;

                if( soma != numero*numero )
                        printf( "Falhou para o numero %llu\n",numero );
        }
}


Esta é a descrição literal do problema, mas nem sempre a descrição literal é a melhor a ser implementada. O que está errado neste programa?

sexta-feira, 13 de novembro de 2015

C: Strings e ponteiros, um caso para pensar

O que está errado com função abaixo:

char mensagem[100] ;

processa()
{
    /* processa */
    if( /* uma condição de erro */ )
        strcpy( mensagem,"Deu erro 1" );
    else
    {
        /* processa */
        if( /* uma condição de erro */ )
            strcpy( mensagem,"Deu erro 2" );
        else
        {
            /* processa */
            if( /* uma condição de erro */ )
                strcpy( mensagem,"Deu erro 3" );
            else
                strcpy( mensagem,"Funcionou direitinho" );
        }
    }
}

Antes de prosseguir lendo, pare e pense um pouco.

C: Sobre strings e uma pequena eliminação de strlen, strcpy

Existem alguns truques que podem ser usados para acelerar processamento de strings, mas exigem uma compreensão de como funcionam as strings em C.

As strings em C são chamadas de Null Terminated Strings, ou strings terminadas por nulo. O caractere null, que é equivalente ao número inteiro zero (note, não é o caractere zero), estará logo após do último caractere da string, marcando que a string terminou.

E o conceito de string se confunde com o array de caracteres. Na realidade, é um array de caracteres, e o que vai ditar se é uma string ou um array de caracteres banal é a forma com que o programador fez o código lidar com ela.

quarta-feira, 16 de setembro de 2015

A fonte de dores de cabeça

Tive umas instabilidades no meu computador, especialmente ligadas a discos.

Eram discos que ficavam erráticos, dando erros, causando panes no sistema etc. Sorte que o FreeBSD, o sistema que uso, lida relativamente bem com estas coisas, dentro do possível. Na versão 10, se um disco dá problemas, sem ser um dos fundamentais do sistema, ele é abandonado, mas o sistema dificilmente dá pane. A versão 11, que estou usando, e que ainda está em desenvolvimento, me pareceu lidar pior com isto.

Eu aposentei alguns HDs por que deram algumas panes, mas paradoxalmente o S.M.A.R.T. tinha me dito que estavam bons. Troquei alguns adaptadores de alimentação, do tipo MOLEX  para SATA, e alguns cabos SATA, e tive poucas melhoras.

Um dos HDs aposentados era o antigo do meu notebook, que estava em um gabinete externo. Ele tinha parado de funcionar.

Recentemente a situação ficou pior, e cheguei a pensar que o HD novo de 4 TB estava morrendo, pois ele dava pane e era abandonado pelo sistema com muita frequência. A piora, em parte, coincidiu com a colocação de um SSD, além dos 5 HDs que costumavam ficar ligados.

Mas a coisa estava caótica demais para parecer que era ele. Fiz trocas de cabos SATA e não deu em nada.

Comecei a desconfiar de problemas de fonte de alimentação, mesmo com o sistema dando panes relacionadas com HDs, e não com placa mãe. A fonte poderia não estar aguentando tanta carga de HDs.

A BIOS tem um recurso que é mostrar as tensões da fonte de alimentação, então, depois de uma das muitas panes, entrei nela para ver. As tensões de 3.3V e 5.0V estavam muito baixas, com cerca de 3.0V e 4.5V respectivamente. Estavam com 10% de erro, que é mais do que os 5% permitidos no padrão esperado. A de 12V estava boa.

Como muita da eletrônica dos HDs dependem da alimentação de 5.0V, usando a de 12V só para os motores, pensei em panes das controladoras dos HDs. E o SSD não tem motor, portanto só deve usar a alimentação de 5.0V, talvez tenha aumentado mais ainda a carga sobre ela.

Num teste rápido, eu desliguei o gravador de DVD e um dos HDs, e as fontes de 3.3V e 5.0V melhoram um pouquinho, com a segunda marcando 4.6V. Mesmo assim o sistema ficou instável, só que menos instável.

Então resolvi arriscar comprar uma fonte nova, de 500W, como a antiga (que eu pensava se de 430W). Foi uma boa compra. Ela é mais silenciosa, e a medição de tensão ficou praticamente cravada, variando cerca de 1% por volta da valor nominal. Isto com 5 HDs internos, um USB e um SSD.

Fui colocando carga, fazendo os testes nos discos, colocando o gravador de DVD etc. O sistema se mostrou estável, bem estável.

No momento estou com 5 HDs internos, 2 USB (o antigo do notebook mencionado acima voltou a funcionar, portanto deveria ser problema com a alimentação de 5.0V), 1 SSD, o gravador de DVD plugados, e está tudo estável.

Fontes de alimentação podem ser fontes de grandes dores de cabeça, além de serem a peça mais chata para substituir num computador. Elas podem sutilmente lhe infernizar a vida.

PS: Agora tenho que retestar um bando de HDs aposentados. Sorte que não joguei-os no lixo.

domingo, 25 de março de 2012

C: Um exemplo de simplificação de expressão lógica

No outro dia vi uma expressão assim:

        if(((situacao == situacao_a) ||
            ((
situacao == situacao_b) && (strcmp(string,UMA_MACRO) == 0))) ||
            ((
situacao == situacao_c) ||
            ((
situacao == situacao_d) && (strcmp(string,UMA_MACRO) == 0))))
        {

                        /* ... */
        }


Este código acima está abaixo do ótimo, tanto em geração de código quanto em desempenho. Mas como otimizar?

Antes de continuar lendo, que tal você mesmo tentar fazer uma versão melhor dele? O artigo sobre avaliação incompleta pode ajudar.

sábado, 3 de março de 2012

C: Contagem de condições lógicas

Digamos que em um algoritmo é necessário que pelo menos 3 de 5 condições sejam verdadeiras para tomar uma ação. Como testar isto? Fazer um emaranhado de if? Pior, se somente 3 de 5 tem que ser verdadeiras? Fazer um emaranhado maior?

C: Avaliação incompleta

Existem duas formas de avaliação em expressões lógicas, a avaliação completa e a incompleta.

Por definição, no Pascal a avaliação sempre é completa (O Turbo Pascal tinha uma opção para mudar este comportamento.), e no C é incompleta.

O que é isto? Quais são as consequências? Como melhor aproveitar isto.

sexta-feira, 24 de fevereiro de 2012

C: Ser ou não ser - Boolean

No C não existe o tipo boolean, tal como existe em outras linguagens, mas existem operações lógicas. As operações lógicas são operações inteiras de baixo nível de precedência.