Conceitos Avançados de Programação em C no Linux

O interpretador de comandos bash oferece suporte para manipulação de vetores esparsos, permitindo criar estruturas de dados indexadas sem necessidade de continuidade nos índices.

Definição de Arrays

Existem duas formas principais de inicializar um vetor:

nome=(valor1 valor2 valor3)

Ou utilizando índices explícitos, que podem ser descontínuos:

nome=([0]=valor1 [5]=valor2 [10]=valor3)

Acessando Elementos

Para obter um elemento específico, utiliza-se a sintaxe:

${nome[índice]}

Operações com Todos os Elementos

Pararetrieve todos os elementos do vetor:

${nome[*]}
${nome[@]}

Informações de Tamanho

Para verificar a quantidade de elementos:

${#nome[*]}
${#nome[@]}

Para obter o comprimento de um elemento específico:

${#nome[índice]}

Slice de Arrays

Extrair porções do vetor:

${nome[*]:posição:quantidade}
${nome[@]:posição:quantidade}

Exercícios Propostos

1. Verificar se o diretório "dados" existe no diretório atual; caso contrário, criá-lo. Copiar todos os arquivos regulares para esse diretório e contar a quantidade transferida.

2. Utilizando vetores, contar todos os arquivos no diretório pessoal do usuário:

arquivos=($(ls ~))
echo ${#arquivos[*]}

3. Contar argumentos informados na linha de comando:

parametros=($*)
echo ${#parametros[*]}

4. Contar arquivos com extensão ".c" no diretório pessoal.


Estrutura de Projetos Multi-arquivo

Projetos de maior porte organizados em vários arquivos fonte e cabeçalhos:

  • principal.c - contém a função main()
  • modulo.c - implementa funções específicas
  • cabeçalho.h - declarações e definições públicas

Conteúdo de um Arquivo de Cabeçalho

Os arquivos .h geralmente incluem:

  • Inclusão de outros cabeçalhos
  • Declarações de funções
  • Definições de tipos estruturados
  • Constantes simbólicas
  • Typedef para tipos personalizados
  • Declarações de variáveis globais

Diferença entre aspas e Colchetes Angulares

#include <stdio.h>
#include "minha_funcao.h"

A diferença está no caminho de busca: colchetes angulares pesquisam apenas no diretório sistema de includes, enquanto aspas首先 verificam o diretório local e, se não encontrar, partem para o diretório sistema.


Compilação Condicional

O pré-processador decide quais trechos de código serão compilados baseado em condições definidas.

Verificação de Definição de Macros

#ifdef MACRO
    código_quando_definido
#else
    código_quando_nao_definido
#endif

Verificação de Valor Lógico

#if CONDIÇÃO
    código_se_verdadeiro
#else
    código_se_falso
#endif

Proteção Contra Inclusão Duplicada

#ifndef IDENTIFICADOR
#define IDENTIFICADOR
/* conteúdo do cabeçalho */
#endif

Esta técnica evita que o mesmo arquivo seja processado múltiplas vezes durante a compilação.


Fases de Compilação com GCC

O compilador GCC processa o código através de quatro etapas distintas:

1. Pré-processamento

Expansiona macros, inclui arquivos, remove comentários. Não verifica syntax errors:

gcc -E fonte.c -o fonte.i

2. Compilação

Converte o arquivo pré-processado para linguagem assembly, verificando erros de syntax:

gcc -S fonte.i -o fonte.s

3. Montagem

Traduz o código assembly para código de máquina (formato objeto):

gcc -c fonte.s -o fonte.o

4. Linkedição

Combina arquivos objeto e bibliotecas para gerar o executável:

gcc fonte.o -o executavel

Comando simplificado: gcc programa.c -o programa gera o binário diretamente.


Utilizando o Make

O Make é um utilitário que gerencia a construção de projetos, compilando apenas os arquivos modificados desde a última build.

Funcionamento

Ao modificar apenas alguns arquivos fonte, o Make identifica as alterações através de timestamps e recompila somente os afetados, economizando tempo de compilação.

Arquivo Makefile

O Makefile define regras de construção do projeto:

alvo: dependências
	comando

Exemplo Prático

app: principal.o utilitario.o
	gcc principal.o utilitario.o -o app
principal.o: principal.c
	gcc -c principal.c -o principal.o
utilitario.o: utilitario.c
	gcc -c utilitario.c -o utilitario.o

Alvos Especiais

.PHONY: limpar
limpar:
	rm -f *.o app

Definir alvo como .PHONY previne conflitos quando existe arquivo com mesmo nome.

Variáveis Personalizadas

Variáveis em Makefile usam sintaxe $(nome):

  • = - atribuição recursiva
  • := - atribuição imediata
  • += - concatenação
  • ?= - atribuição condicional

Variáveis Pré-definidas

  • CC - compilador C (padrão: cc)
  • CFLAGS - opções do compilador
  • RM - comando de remoção (padrão: rm -f)

Versão Otimizada do Mkaefile

PROGRAMA=app
FONTES=$(wildcard *.c)
OBJETOS=$(patsubst %.c,%.o,$(FONTES))
CC=gcc
FLAGS=-c -g -Wall

all: $(PROGRAMA)

$(PROGRAMA): $(OBJETOS)
	$(CC) $^ -o $@

%.o: %.c
	$(CC) $(FLAGS) $< -o $@

.PHONY: limpar
limpar:
	$(RM) $(OBJETOS) $(PROGRAMA)

Variáveis Automáticas

  • $< - primeira dependência
  • $@ - nome do alvo
  • $^ - todas as dependências (sem duplicatas)

Funções Úteis

wildcard -Localiza arquivos conforme padrão:

$(wildcard *.c)

patsubst -Substitui padrões em strings:

$(patsubst %.c,%.o,arquivo1.c arquivo2.c)

Resultado: arquivo1.o arquivo2.o

Tags: Bash shell Arrays Makefile gcc

Publicado em 7-4 23:47