Linguagem C dicas sobre programação

porRicardo Jorge

Linguagem C dicas sobre programação

No artigo Linguagem C dicas sobre programação será mostrado que algumas opções de programação podem gerar efeitos diferentes do esperado.

Ao longo dos anos de uso e com a experiência adquirida, acabamos definindo nossas formas prediletas de codificação.

Entretanto, em alguns casos é necessário avaliar se o resultado será consistente e principalmente, o que esperamos.

Além disto, algumas formas de codificação melhoram o desempenho do código, permitindo que aquele hardware mais “simples”, possa ser usado em nosso projeto.

A linguagem C é bastante flexível e expressiva; essas são algumas das razões pelas quais ela tem sido bem-sucedida e resiliente à substituição por linguagens “melhores”.

Um exemplo de sua flexibilidade é a possibilidade de escrever uma expressão de várias maneiras que são funcionalmente equivalentes.

Isso permite que o estilo de codificação seja adaptado às necessidades pessoais.

No entanto, há um problema: às vezes, o código aparentemente equivalente tem diferenças sutis.

Isso pode ocorrer no código mais simples e exploraremos algumas possibilidades neste artigo.

É comum para linguagem C, fornecer várias maneiras diferentes de fazer algo, sendo todas equivalentes.

Por exemplo, dado que x é uma variável do tipo integer ( int ), cada uma das seguintes instruções fará exatamente o mesmo trabalho:

x = x + 1;
x += 1;
x++;
++x;

Em todos os casos, 1 será adicionado a x.

A única diferença é que dependendo do compilador, um código ligeiramente melhor poderá ser gerado para as duas últimas opções.

As duas formas de uso do operador ++, produzem o mesmo resultado.

No entanto, se o valor da expressão for usado, o pré-incremento e o pós-incremento são diferentes, assim:

y = x++;   // y terá o valor de x antes do incremento
y = ++x;   // y terá o valor de x após o incremento

Curiosamente, o pós-incremento é um pouco mais “pesado”, pois o armazenamento precisa ser alocado para manter o valor antigo de x.

No entanto, um compilador provavelmente otimizaria isso.

Se o armazenamento for alocado quando o valor da expressão não for usado, siginifica que o compilador usado não é o mais indicado !

Se, em vez de ser um int, x fosse um ponteiro para int, adicionar 1 teria o efeito de adicionar 4 (em uma máquina de 32 bits).

No entanto, às vezes, construções que parecem ser equivalentes têm diferenças muito sutis.

Provavelmente, a coisa mais simples que você pode fazer em qualquer linguagem de programação é atribuir um valor a uma variável.

Neste caso, poderíamos escrever o seguinte em C :

alpha = 99;
beta = 99;
gamma = 99;

Claro, uma forma mais compacta ficaria assim:

alpha = beta = gamma = 99;

Será que estas duas formas descritas são 100% equivalentes ?

Na maioria das vezes, essas duas construções são inteiramente equivalentes, mas existem (pelo menos) quatro situações em que escolher uma ou outra pode fazer a diferença:

Em primeiro lugar, e de forma mais comum, cada variável é separada e talvez um comentário indicando por que ela está definida com esse valor seja apropriado.

Em segundo lugar, é sempre bom escrever código sustentável.

Talvez, em algum momento no futuro, o código precise ser alterado para que todas as três variáveis ​​não sejam definidas com o mesmo valor.

O primeiro formato se presta mais facilmente a modificações.

O terceiro motivo está relacionado a compiladores abaixo do padrão, que podem gerar código como este para a primeira construção:

mov r0, #99
mov alpha, r0
mov r0, #99
mov beta, r0
mov r0, #99
mov gamma, r0

A segunda construção dá a dica de que r0 só precisa ser carregado uma vez.

Novamente, um compilador melhor não precisaria da dica.

Por último, há a questão da ordem de execução.

Na primeira construção, é totalmente claro que alfa será atribuído primeiro e gama por último.

Um compilador interpretará a segunda construção assim:

alpha = (beta = (gamma = 99));

Isso significa que a ordem de atribuição foi invertida.

Será que isso importa?

Na maioria das vezes, não.

Mas se fossem registradores de dispositivos, não variáveis ​​comuns, isso poderia fazer uma grande diferença.

É muito comum que o hardware precise que os valores de configuração sejam carregados em uma sequência precisa.

Portanto, eu diria que as atribuições múltiplas em uma construção de instrução devem ser evitadas.

No geral, embora C seja uma linguagem pequena, pode-se argumentar que ela poderia ser ainda menor, fornecendo menos maneiras de fazer as coisas.

O resultado pode ser um código mais claro e sustentável.

Artigo baseado nesta publicação.

Artigos relacionados

Função switch e a máquina de estado – state machine

arduino – como melhorar a precisão da entrada analógica



Photo by Niclas Illg on Unsplash

Sobre o Autor

Ricardo Jorge administrator

Deixe uma resposta