Loops For Não Ortodoxos

por Fabio A. Mazzarino

É comum programadores C/C++ com certa experiência não saberem como exatamente funciona o loop for. A maioria aprende um paralelo entre o For-To-Next e o for e não fica sabendo do verdadeiro poder do for em C/C++.

Veja o exemplo abaixo que valida a versão de um conjunto de nós:

for (ctnode = nnodes; ctnode--; )
    if (strcmp(refversion, nodes[ctnode].version)
        break;
if (ctnode >= 0)
    TRACE(TRACE_ERROR, "Not all nodes in same version, aborting");

O código acima não contém nenhum erro. Mas contém uma construção um pouco controversa, um for não ortodoxo. Em algumas equipes de desenvolvimento esse tipo de construção é proibida, em outras amplamente utilizado. Não existe consenso, por mim, é válido e até mais rápido.

Mas um desenvolvedor C/C++ precisa entender como funciona um for.

Como Funciona?

O for em C/C++ é na verdade um while com inicialização e iteração embutidos. O for abaixo:

for (<INIT>; <COND>; <ITER>) {
    <STATEMENTS>
}

É equivalente ao while:

<INIT>
while (<COND>) {
    <STATEMENTS>
    <ITER>
}

Vamos, então, refazer o for do trecho de código como se fosse um while:

ctnode = nnodes;
while (ctnode--) {
    if (strcmp(refversion, nodes[ctnodes].version)
        break;
}

Não podemos esquecer do incremento pós-fixado:

while (ctnode--)

Executa a seguinte sequência:
1. verifica se ctnode é zero, se for sai do loop
2. decrementa o valor de ctnode

Dessa forma na primeira passada do loop o valor de ctnode não é nnodes, o que causaria um index out-of-bounds, mas sim nnodes – 1, o que indexa corretamente o último valor do array. E a última passada a condição resolve como 1, mas dentro do loop como 0. E em caso de sucesso o valor de ctnodes é -1.

E o break?

O break, e o if após o loop, é o que torna essa construção ainda mais interessante. Quando o loop é interrompido o contador não chegou a zero. Portanto detecta-se a interrupção através de um teste no contador, se o contador não for negativo, sucesso.

E pra finalizar o valor em ctnode após o loop contém o índice do node que que está com versão errada.

E Ainda Tem a Performance

Em sistemas embarcados aonde qualquer tipo de otimização conta, utilizar a construção proposta aumenta a performance, pois a saída do loop é feita com uma condição que testa zero, muito mais rápida para qualquer processador, e depois a verificação de erro é também testada com um teste de zero. Portanto a solução tem mais performance que a mais ortodoxa.

Quando Não Usar?

Por que algumas pessoas não recomendam a construção não ortodoxa do for? Essa construção é bem típica da linguagem C/C++, e é completamente não ortodoxa, muitos programadores não entendem como de fato funciona o for, e ao encontrar tal solução não conseguem interpretá-lo de maneira correta.

Se na sua base de desenvolvedores houver muitos programadores pouco experientes, ou com conhecimento superficial de C/C++ é melhor não utilizar a construção. Afinal tão importante quanto a performance da aplicação é a performance da manutenção.