Diretivas de pré-processamento e namespaces em C++

Diretivas de pré-processamento e namespaces em C++

Tarefas de pré-processamento são tarefas que ocorrem antes que um programa seja efetivamente compilado. No pré-processamento, as principais operações realizadas antes da compilação incluem:

  • Definição de Constantes Simbólicas
  • Inclusão de outros arquivos no arquivo a ser compilado
  • Definição de Macros
  • Compilação condicional de código
  • Execução condicional de diretivas

As tarefas de pré-processamento são definidas por diretivas de pré-processamento no C++. Todas as diretivas de pré-processador se iniciam com o símbolo #, e não podemos ter nenhum caractere antes de uma diretiva em uma linha, exceto espaços em branco.

Como as diretivas de pré-processamento não são declarações do C++ (comandos), elas não terminam com ponto-e-vírgula ;. Colocar o símbolo ; no final de uma diretiva de pré-processamento é, na verdade, um erro de programação comum.

Diretivas de pré-processador em C++

São instruções direcionadas ao compilador. podemos fornecer algumas instruções ao compilador de modo que antes de iniciar o processo de compilação essas instruções são executadas.

Alguns exemplos de diretivas de pré-processador incluem:

  • #define – define constantes simbólicas (que não ocupam espaço na memória RAM do sistema)
  • #ifndef – define um item se ele não tiver sido definido anteriormente
  • #include – inclusão de cabeçalhos – ver a seguir.

Todo código em C++ inicia com a diretiva #include<>. A diretiva instrui o pré-processador a incluir uma parte do código padrão do C++ ou outro código pronto no programa atual. Vejamos algumas dessas diretivas com mais detalhes agora.

Diretiva de pré-processamento #include

A diretiva de pré-processamento #include faz com que uma cópia de um arquivo específico seja incluído no código, no lugar da diretiva. É empregada geralmente para incluir arquivos de cabeçalho padrão como por exemplo o <iostream>.

Há duas formas de se escrever uma diretiva #include:

#include <arquivo>
#include "arquivo"

A primeira forma, com <>, é empregada para a inclusão de arquivos de cabeçalho da biblioteca padrão C++. O pré-processador procura o arquivo especificado em pastas pré-definidas no computador.

Já na segunda forma, com o nome do arquivo entre aspas “”, o pré-processador procura o arquivo primeiramente na mesma pasta (diretório) onde se encontra o arquivo a ser compilado, e então nos diretórios pré-definidos pela implementação do sistema. No geral, usamos essa forma quando queremos incluir arquivos de cabeçalho definidos pelo usuário (criados por nós mesmos).

Por exemplo, a diretiva

#include<iostream>

inclui o cabeçalho de nome iostream para dar suporte a operações de entrada e saída de dados, por exemplo disponibilizando funções para ler dados da tela e escrever no console.

Diretivas de pré-processamento #define

Com uma diretiva #define criamos Constantes Simbólicas, que são constantes representadas como símbolos, e Macros, que são pequenas operações funcionais. Escrevemos uma diretiva #define da seguinte forma:

#define identificador valor_substituto

Com esta declaração, todas as ocorrências do identificador no código são substituídas pelo valor_substituto informado. Por exemplo, considere a constante simbólica a seguir:

#define distancia 150

Toda vez que aparecer o identificador distância no código (exceto se estiver entre aspas), ele será substituído pelo valor 150. Note que NÃO usamos o operador de atribuição = aqui, pois não se trata de uma atribuição de valores, e sim de uma substituição de nomes.

Uma constante simbólica não aloca espaço na memória RAM do sistema e não armazena dado nenhum. No geral, é preferível criar constantes “comuns” em C++ com a palavra-chave const, em vez de usar constantes simbólicas, pois isso facilita o debugging do código – mas as constantes comuns ocupam espaço na memória, o que também deve ser levado em consideração.

Vejamos outro exemplo da diretiva #define, desta vez criando uma macro.

Uma macro é uma operação (pequena função) definida em uma diretiva de pré-processamento, e que podem ou não receber argumentos. O exemplo a seguir mostra a definição de uma macro que realiza o cálculo da área de um triângulo retângulo, dada por A = 1/2 * b * h (base * altura / 2):

#define AREA_TRIAN(b, h) ((b * h)/2)

Toda vez que AREA_TRIAN(b, h) aparecer no código, os valores de b e h serão substituídos pelos valores fornecidos como argumentos, e será retornado o valor calculado da área do triângulo retângulo. Assim, se em algum ponto do código tivermos:

area = AREA_TRIAN(10,15)

a variável area receberá o retorno da execução da macro, ou seja: 10 * 15 / 2 = 75.

Uma vantagem do uso de macros em relação à declaração de funções comuns no código é que o código é inserido diretamente no programa, diminuindo a sobrecarga associada à criação de funções. Porém, em C++ é muito comum que as macros sejam substituídas por outras formas de declaração de funções, como templates e funções inline ou funções lambda. As macros são empregadas mais extensivamente em linguagem C.

Compilação Condicional

Com uma estrutura de compilação condicional podemos controlar a execução das diretivas de pré-processamento e, assim, a compilação do código-fonte como um todo. Com uma diretiva de pré-processamento condicional, as expressões são avaliadas e será determinado se o código associado será compilado ou não. O exemplo mais comum de diretiva condicional é a diretiva #ifndef (“IF NOT DEFINED”). Veja o exemplo a seguir:

#ifndef NULL
  #define NULL 0
#endif

Esta diretiva verifica se uma constante simbólica NULL não está definida. Se estiver definida, nada ocorre, mas se ainda não estiver definida, a constante simbólica será criada com o valor 0.

Note que a diretiva #ifndef deve ser fechada (terminada) com #endif. Também existe uma diretiva que verifica se uma constante já está definida, que é a constante #ifdef (“IF DEFINED”), a qual, como se espera, funciona de forma inversa à #ifndef.

Linguagem de Programação C++

Namespaces e diretivas using

Todos os programas em C++ iniciam sua execução a partir de uma função especial chamada de main(), independente de onde ela esteja declarada no código do programa. Seu formato é o seguinte:

int main() {
    // Código principal do programa
}

As chaves indicam onde inicia e onde termina o bloco de código que é executado pela função.

Diretivas using

As diretivas using habilitam um programa a usar todos os nomes em qualquer cabeçalho C++ padrão, como por exemplo o cabeçalho <iostream>. Assim, podemos incluir em um programa o namespace std da seguinte forma:

using namespace std;

E desta forma iremos poupar digitação de código posteriormente quando precisarmos utilizar as funções e métodos deste namespace, pois não será necessário referenciá-lo a todo instante. 

Por conta disso, em vez de escrevermos:

std::cout << "Mensagem"

podemos escrever simplesmente:

cout << "Mensagem"

Pois o compilador já saberá que a função cout pertence ao namespace std, declarado por meio da diretiva using.

Namespaces em C++

Um namespace (espaço de nomes) é uma forma de organização de funções e outros elementos de um programa. São úteis para remover conflitos de nomes entre recursos distintos, como arquivos de cabeçalho que possuam funções ou métodos de mesmo nome, mas com funcionalidades distintas.

Exemplo de namespaces em C++

No exemplo a seguir

#include <iostream>
#include <locale>

namespace ex1 {
    void func() {
        std::cout << "Bóson ";
    }
}
namespace ex2 {
    void func() {
        using namespace std;
        cout << "Treinamentos" << endl;
    }
}

using namespace ex1;
using namespace std;

int main() {
    setlocale(LC_ALL, "");    
    func();
    ex2::func();
}

Saída obtida:

Bóson Treinamentos

A palavra “Bóson” vem do retorno da função func() definida no namespace ex1, e apalavra “Treinamentos” vem da função de mesmo nome, func(), porém do namespace ex2. Incluímos o cabeçalho locale e a declaração setlocale(LC_ALL, “”); para termos suporte aos caracteres especiais da língua portuguesa (e outros) no console, como a letra o acentuada da palavra “Bóson”.

Podemos manter os namespaces em arquivos de cabeçalho separados, e incluir esses cabeçalhos no código para ter acesso às suas funções quando necessário, a partir de outra parte do programa.

std: Biblioteca Padrão (standard). Indica o namespace padrão da linguagem, que trata de uma série de comandos, funções e declarações distintas.
Pode ser declarado no início do código, logo após as diretivas #include, com o uso da declaração using:

#include<iostream>
using namespace std;

Ou ainda usado diretamente no código do programa, precedendo os nomes das funções a serem invocadas (método mais trabalhoso):

std::cout << "Olá\n";
  • O símbolo :: é o operador de resolução de escopo.
  • cout é uma função que pertence ao namespace padrão (std). significa Character OUTput (saída de caracteres), e permite escrever dados na saída padrão do computador (tela).
  • << é o operador de inserção, que permite inserir o que é colocado à sua direita no elemento que está à sua esquerda. No caso, a palavra Olá é “inserida” no objeto cout – ou seja, enviada para a tela.

Conclusão

Estudamos nesta lição as diretivas de pré-processamento principais do C++, como as diretivas #include, #define e #ifndef, e aprendemos os conceitos de constante simbólica, macro e arquivo de cabeçalho.

Também vimos o que é um namespace e a diretiva using, e entendemos que um programa em C++ sempre inicia com a função main().

É isso aí! A partir da próxima lição vamos iniciar os estudos da sintaxe do C++, aprendendo sobre tipos de dados e declaração e atribuição de variáveis. Até!

Sobre Fábio dos Reis (1195 Artigos)
Fábio dos Reis trabalha com tecnologias variadas há mais de 30 anos, tendo atuado nos campos de Eletrônica, Telecomunicações, Programação de Computadores e Redes de Dados. É um entusiasta de Ciência e Tecnologia em geral, adora Viagens e Música, e estuda idiomas, além de ministrar cursos e palestras sobre diversas tecnologias em São Paulo e outras cidades do Brasil.

Escreva um comentário

Seu e-mail não será divulgado


*