Photo by Shamin Haky on Unsplash

Des[C]omplicando o C - 1 — Primeiro contato

Arthur Fernandes

--

Linguagem C. Só de falar dela, há pessoas quem sinta calafrios. Mas por que será que uma das mais tradicionais linguagens de programação, envolvida no desenvolvimento de diversos projetos muito utilizados desde os anos 1970 e queridinha dos sistemas embarcados é tão temida por grande parte das pessoas que programam? Com certeza, ao perguntar às pessoas que temem a linguagem, muitas respostas distintas serão recebidas.

Há pessoas que dirão que C é uma linguagem muito difícil, que é uma linguagem de baixo nível, ou até mesmo que não faz sentido sua utilização, porque muito do que se tem que fazer manualmente na linguagem, já está pré-implementado em linguagens mais populares hoje em dia, como é o caso do Python, JavaScript e Java.

Apesar de apenas a última afirmação ser verdadeira, é bastante compreensível que as pessoas pensem assim sobre C, afinal, muitos cursos superiores de tecnologia escolhem a linguagem como primeiro contato dos alunos e alunas com programação, e devido à curva de aprendizagem ser mais brusca do que muitas linguagens que são, hoje, consideradas de mais alto nível. O motivo desta curva ser tão íngreme talvez tenha alguma relação à sintaxe ter muitas regras, desviando o foco da lógica de programação e arquitetura de código, pois fazer o código compilar se torna uma preocupação, o que não acontece com linguagens como Python, onde a sintaxe é simples, o que permite que a preocupação se limite principalmente ao comportamento do sistema.

Pode ser que se a estrutura dos cursos de graduação mudasse, a ponto de priorizar linguagens com sintaxe mais simples no primeiro contato de seus estudantes com programação, a linguagem C não colocasse tanto medo quanto o faz. Mas o fato é que não existe uma grande movimentação hoje pra que isso mude, então pode ser que a linguagem C continue amedrontando muitas pessoas iniciantes por um bom tempo.

Por este motivo, estou iniciando uma série de artigos para falar sobre a linguagem C e buscar descomplicá-lá, a fim de ajudar pessoas iniciantes que têm passado por dificuldades no aprendizado desta tecnologia e, com sorte, desmistificar todo o medo que a cerca.

Cumprimentando a linguagem

A linguagem C pode ser muito densa e cheia de conteúdo: variáveis, funções, ponteiros, gerenciamento de memória, estruturas de dados, bibliotecas e muito mais. No entanto, todos esses assuntos podem ser aprendidos por qualquer pessoa, desde que seja seguida uma cadência apropriada, onde seja possível entender a base deles de forma profunda, o que torna as complicações cada vez menores.

Sendo assim, precisamos seguir um determinado ritmo de estudos que abranja, passo a passo, os principais recursos da linguagem e que possibilite o desenvolvimento da autonomia para estudar recursos mais avançados. Quando uma casa é construída, é de suma importância um sólido alicerce (base). Quando a base é forte o suficiente, é muito mais fácil construir cada parede sem o risco de desmoronamento. A mesma máxima se aplica aos estudos em qualquer área, e dentro da linguagem C, um excelente ponto de partida é de onde todo mundo começa: o ‘Hello World’!


#include <stdio.h>

int main(void){

printf("%s", "Hello, World!");

return 0;
}

O trecho de código acima (que a primeira vista pode parecer um monte de palavras mágicas, à vista de quem nunca teve contato com C, ou até mesmo um código bastante simples, aos olhos de quem já estudou a linguagem), apesar de apenas imprimir no console a famosa frase “Hello, World!”, já nos traz muitos elementos importantes da linguagem, que serão utilizados em todos os programas nela escritos. Vamos analisar linha a linha?

Logo no início, encontramos uma série de sinalizações que se diferem do restante do código:

#include <stdio.h>

Nesse trecho, estamos conversando com o compilador e pedindo para que ele inclua (como os criadores da linguagem gentilmente sugerem ao escolher a palavra `include`) uma série de funções pré-escritas que a linguagem tem dentro da biblioteca `<stdio.h>`, que nada mais nada menos é uma abreviação para Standard Input and Output, ou Entrada e Saída Padrões. Nesta biblioteca, podemos encontrar diversas funções disponibilizadas pelos desenvolvedores do C que tratam de entrada e saída de dados, inclusive uma função que veremos logo menos: a `printf()`. Às instruções que recebem em seu início o caractere #, chamaremos de Diretivas de Compilação.

Logo após a diretiva apresentada, nos deparamos com um bloco de código que, como o nome já indica, delimita a parte principal do nosso programa. Blocos de código, como o citado, são delimitados pelos caracteres `{}`, ou chaves; podemos dizer, portanto, que sua utilização define um bloco de código, também muito conhecido como escopo.

Podemos perceber, ainda, uma série de palavras que antecedem o escopo:

int main(void){}

Estas instruções são responsáveis por definir do que se trata o escopo que a sucede e dentro da linguagem C, quando juntas são chamadas de assinatura de função, um recurso muito importante e que terá um artigo detalhado apenas para explicar seu funcionamento. Dito isso, nesse momento podemos entender por função uma instrução que executa uma determinada rotina. Vamos olhar, então, para essa assinatura e tentar tirar proveito do que ela pode nos oferecer nesse primeiro momento:

Logo em seu início, temos a palavra-chave `int`, que dentro do contexto nos indica que a função vai retornar um valor inteiro, como podemos ver pela última linha do bloco `return 0`, onde está sendo retornado o valor 0. Não se preocupe nesse momento com o que exatamente é esse retorno, pois falaremos sobre isso mais para frente, mas é interessante saber que o retorno 0 é característico de quando o programa é executado sem falhas.

Seguido disso, temos a palavra `main` que, na verdade, não se trata de uma palavra chave da linguagem, apesar de ter função especial para o compilador. Dentro do contexto da função, podemos dizer que `main` é seu nome, ou seja, é o jeito que o compilador vai identificar essa função para que ela seja executada no programa. Porém, por se tratar de uma função `main`, a principal do programa, o que acontece na prática é que o compilador procura por uma função com esse nome específico para saber como executar o programa. Sendo assim, o compilador procura por essa função `main` quando o programa é rodado e executa, linha a linha, o bloco de código que ela carrega.

É importante salientar, também, a existência de um par de parênteses colados em `main`, que comumente serão vistos quando estamos utilizando funções, pois foi a sinalização que os criadores da linguagem definiram. Esses parênteses têm significado alterado quando os utilizamos em diferentes contextos: ao utilizá-los em uma assinatura de função, como é o caso, eles servem para definir valores que essa função deve receber para operar, sendo uma possibilidade também que a função não receba nada, ou seja, possa operar sem precisar de nenhuma informação adicional. Nesses casos, é comum ver o parêntese vazio, ou com a palavra-chave `void`, como é o caso da main.

O outro contexto que nos interessa é o que pode ser visto na linha de código que nos resta analisar:

printf("%s", "Hello, World!");

Onde, novamente, os parênteses aparecem juntos de uma palavra, o que nos indica que estamos lidando com uma função. Diferente do caso anterior, é possível perceber que não há a palavra `int` antes da função. Isso acontece, pois não estamos mais definindo uma função através da sua assinatura, mas apenas utilizando uma função pré-escrita que se encontra naquela biblioteca `<stdio.h>` que foi incluída na aplicação logo na primeira linha, o que já nos dá uma ideia sobre seu funcionamento: entrada ou saída de dados.

Se ao definir a assinatura de uma função os parênteses servem para definir que tipo de dado a função vai receber para operar, quando uma função é chamada, ela vai receber os valores definidos pela sua assinatura.

No caso do exemplo, temos a `printf()`, que imprime no console um texto que pode ser definido, como no caso acima, a partir de uma máscara de tipo (o %s), que vai dar seu espaço ao texto Hello, World! que está após a vírgula. Ou seja, nessa função estamos recebendo dois valores textos para que ela imprima um valor na tela.

Conclusão

Com isso, vimos que mesmo em um trecho simples de código, que mostra um valor na tela, encontramos elementos essenciais da linguagem que, ao serem aprofundados, recebem uma significação ainda maior e trazem um grau de entendimento que facilita a leitura de qualquer código e, por consequencia, a escrita de software na linguagem C.

Para cada linha de código seria possível uma explicação ainda maior e mais aprofundada, que serão abordadas nos próximos artigos da série, bucando sempre a didática e explicações detalhadas de cada recurso da linguagem em um ritmo cadenciado para que não hajam confusões entre as diferentes funcionalidades que ela traz, para que, um passo de cada vez, seja construído um sólido alicerce, a fim de desmistificar e simplificar a linguagem C.

--

--