Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Herramientas de Desarrollo para C

Universidad Nacional de Rio Negro - Sede Andina

Esta guía detalla la instalación y uso de herramientas esenciales para el desarrollo profesional en C. Estas herramientas te ayudarán a detectar errores, depurar código y mantener la calidad del software.

Tabla de Contenidos


Cppcheck: Análisis Estático de Código

Cppcheck es una herramienta de análisis estático que detecta errores en el código sin necesidad de ejecutarlo. Identifica problemas como accesos fuera de límites, fugas de memoria, condiciones redundantes y más.

Instalación

En Windows

  1. Descargar el instalador:

  2. Ejecutar el instalador:

    • Hacé doble clic en el archivo descargado

    • Seguí el asistente de instalación

    • Marcá la opción “Add to PATH” si está disponible

  3. Verificar la instalación:

    cppcheck --version

En Linux (Debian/Ubuntu)

sudo apt update
sudo apt install cppcheck

En Linux (Fedora/RHEL)

sudo dnf install cppcheck

En macOS

brew install cppcheck

Uso Básico

Análisis de un Archivo Individual

cppcheck archivo.c

Análisis con Más Verificaciones

cppcheck --enable=all --suppress=missingIncludeSystem archivo.c

Opciones explicadas:

Análisis de Todo un Proyecto

cppcheck --enable=all --suppress=missingIncludeSystem src/

Interpretación de Resultados

Cppcheck reporta diferentes tipos de problemas:

Tipo

Severidad

Descripción

error

Alta

Errores que causarán fallas en tiempo de ejecución

warning

Media

Código potencialmente problemático

style

Baja

Sugerencias de estilo y mejora

performance

Media

Optimizaciones posibles

portability

Media

Problemas de portabilidad entre plataformas

Ejemplo Práctico

Considerá el siguiente código con errores:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr = malloc(10 * sizeof(int));
    
    for (int i = 0; i <= 10; i++) {  // Error: acceso fuera de límites
        arr[i] = i;
    }
    
    // Error: no se libera la memoria
    return 0;
}

Al ejecutar cppcheck:

cppcheck ejemplo.c

Salida esperada:

[ejemplo.c:6]: (error) Array 'arr[10]' accessed at index 10, which is out of bounds.
[ejemplo.c:4]: (error) Memory leak: arr

Valgrind: Detección de Errores de Memoria

Valgrind es una suite de herramientas para debugging y profiling. Su herramienta más utilizada, Memcheck, detecta fugas de memoria, accesos inválidos y otros problemas relacionados con el manejo de memoria.

Instalación

En Linux (Debian/Ubuntu)

sudo apt update
sudo apt install valgrind

En Linux (Fedora/RHEL)

sudo dnf install valgrind

En macOS

brew install valgrind

En Windows (usando WSL)

  1. Instalar WSL:

    wsl --install
  2. Dentro de WSL, instalar Valgrind:

    sudo apt update
    sudo apt install valgrind

Uso Básico

Compilación para Valgrind

Para obtener información detallada en los reportes, compilá con símbolos de debugging:

gcc -g -Wall -Wextra programa.c -o programa

La opción -g incluye información de debugging que permite a Valgrind mostrar números de línea.

Ejecución con Valgrind

valgrind ./programa

Opciones Recomendadas

Para un análisis más completo:

valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./programa

Opciones explicadas:

Tipos de Errores que Detecta

Error

Descripción

Ejemplo

Invalid read/write

Acceso a memoria no asignada

arr[100] en array de 10

Memory leak

Memoria asignada nunca liberada

malloc() sin free()

Use of uninitialized value

Uso de variable sin inicializar

int x; printf("%d", x);

Invalid free

Liberar memoria ya liberada

free(ptr); free(ptr);

Mismatched free

Liberar con función incorrecta

new[] con free()

Ejemplo Práctico

Código con errores de memoria:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr = malloc(5 * sizeof(int));
    
    // Error 1: Acceso fuera de límites
    arr[10] = 42;
    
    // Error 2: Uso de variable no inicializada
    int x;
    printf("Valor: %d\n", x);
    
    // Error 3: Memory leak (no se llama a free)
    return 0;
}

Compilación y análisis:

gcc -g -Wall -Wextra ejemplo.c -o ejemplo
valgrind --leak-check=full ./ejemplo

Salida parcial de Valgrind:

==12345== Invalid write of size 4
==12345==    at 0x401234: main (ejemplo.c:7)
==12345==  Address 0x... is 0 bytes after a block of size 20 alloc'd

==12345== Conditional jump or move depends on uninitialised value(s)
==12345==    at 0x401245: main (ejemplo.c:10)

==12345== LEAK SUMMARY:
==12345==    definitely lost: 20 bytes in 1 blocks

GDB: GNU Debugger

GDB es el debugger estándar para C/C++ en sistemas Unix-like. Permite ejecutar programas paso a paso, inspeccionar variables, establecer breakpoints y analizar el comportamiento del programa en tiempo de ejecución.

Instalación

En Windows (MinGW incluye GDB)

Si instalaste GCC mediante MinGW (como se describe en la guía de GCC), GDB ya está disponible.

Verificá la instalación:

gdb --version

En Linux (Debian/Ubuntu)

sudo apt update
sudo apt install gdb

En Linux (Fedora/RHEL)

sudo dnf install gdb

En macOS

brew install gdb

Compilación para Debugging

Para usar GDB efectivamente, compilá tu programa con la opción -g:

gcc -g -Wall -Wextra programa.c -o programa

Comandos Básicos de GDB

Iniciar GDB

gdb ./programa

Comandos Fundamentales

Comando

Abreviación

Descripción

run [args]

r

Ejecuta el programa

break <ubicación>

b

Establece un breakpoint

next

n

Ejecuta la siguiente línea (sin entrar en funciones)

step

s

Ejecuta la siguiente línea (entrando en funciones)

continue

c

Continúa la ejecución hasta el próximo breakpoint

print <variable>

p

Muestra el valor de una variable

list

l

Muestra el código fuente

backtrace

bt

Muestra la pila de llamadas

quit

q

Sale de GDB

Ejemplo Práctico de Debugging

Considerá un programa con un bug:

#include <stdio.h>

int calcular_suma(int n) {
    int suma = 0;
    for (int i = 1; i < n; i++) {  // Bug: debería ser i <= n
        suma += i;
    }
    return suma;
}

int main() {
    int resultado = calcular_suma(5);
    printf("Suma: %d\n", resultado);  // Esperado: 15, Obtiene: 10
    return 0;
}

Sesión de Debugging

# Compilar con información de debug
gcc -g suma.c -o suma

# Iniciar GDB
gdb ./suma

Dentro de GDB:

(gdb) break main
Breakpoint 1 at 0x401156: file suma.c, line 11.

(gdb) run
Starting program: ./suma
Breakpoint 1, main () at suma.c:11
11          int resultado = calcular_suma(5);

(gdb) step
calcular_suma (n=5) at suma.c:4
4           int suma = 0;

(gdb) next
5           for (int i = 1; i < n; i++) {

(gdb) print i
$1 = 1

(gdb) continue
Suma: 10

(gdb) quit

Comandos Avanzados

Watchpoints (Puntos de Observación)

Detiene la ejecución cuando una variable cambia:

(gdb) watch variable

Breakpoints Condicionales

(gdb) break suma.c:5 if i == 3

Examinar Memoria

(gdb) x/10d &array    # Muestra 10 enteros desde la dirección de array

Pretty Printing de Estructuras

(gdb) set print pretty on
(gdb) print mi_estructura

Otras Herramientas Útiles

AddressSanitizer (ASan)

AddressSanitizer es una herramienta de detección de errores de memoria integrada en GCC y Clang. Es más rápida que Valgrind pero requiere recompilación.

Uso

gcc -g -fsanitize=address -fno-omit-frame-pointer programa.c -o programa
./programa

Ventajas

UndefinedBehaviorSanitizer (UBSan)

Detecta comportamiento indefinido en C:

gcc -g -fsanitize=undefined programa.c -o programa
./programa

Detecta:

Gcov: Cobertura de Código

Gcov mide qué partes del código se ejecutan durante las pruebas:

gcc -fprofile-arcs -ftest-coverage programa.c -o programa
./programa
gcov programa.c

Genera un reporte mostrando qué líneas se ejecutaron.

Gprof: Profiling de Rendimiento

Identifica qué funciones consumen más tiempo:

gcc -pg programa.c -o programa
./programa
gprof programa gmon.out > analisis.txt

Flujo de Trabajo Recomendado

Checklist de Calidad

Antes de entregar un trabajo práctico, verificá:


Integración con VS Code

Visual Studio Code puede integrar estas herramientas para facilitar su uso.

Extensiones Recomendadas

  1. C/C++ (Microsoft): Soporte básico para C

  2. C/C++ Extension Pack: Bundle de extensiones útiles

  3. Cppcheck Extension: Integración de cppcheck

  4. Native Debug: Soporte para GDB

Configuración de Tasks

Creá un archivo .vscode/tasks.json en tu proyecto:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Compile with Debug",
            "type": "shell",
            "command": "gcc",
            "args": [
                "-g",
                "-Wall",
                "-Wextra",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "Run Cppcheck",
            "type": "shell",
            "command": "cppcheck",
            "args": [
                "--enable=all",
                "--suppress=missingIncludeSystem",
                "${file}"
            ]
        },
        {
            "label": "Run Valgrind",
            "type": "shell",
            "command": "valgrind",
            "args": [
                "--leak-check=full",
                "--show-leak-kinds=all",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "dependsOn": ["Compile with Debug"]
        }
    ]
}

Configuración de Launch para GDB

Creá un archivo .vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "GDB Debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "preLaunchTask": "Compile with Debug"
        }
    ]
}

Recursos Adicionales

Documentación Oficial

Tutoriales Interactivos

Cheat Sheets

Comandos Rápidos

Herramienta

Comando Más Usado

Propósito

Cppcheck

cppcheck --enable=all archivo.c

Análisis estático completo

Valgrind

valgrind --leak-check=full ./programa

Detección de fugas de memoria

GDB

gdb ./programarunbacktrace

Debugging interactivo

ASan

gcc -fsanitize=address -g archivo.c

Detección rápida de errores


Conclusión

El dominio de estas herramientas es fundamental para desarrollar software de calidad en C. Incorporarlas en tu flujo de trabajo te ayudará a:


Ejercicios Prácticos

:label: ex-herramientas-1

Creá un programa en C que tenga al menos tres errores diferentes (fuga de memoria, acceso fuera de límites, variable no inicializada). Luego:

1. Usá Cppcheck para identificar errores estáticos
2. Compilá y ejecutá con Valgrind
3. Corregí todos los errores reportados
4. Verificá que el programa pase todas las verificaciones
:label: ex-herramientas-2

Tomá uno de tus ejercicios anteriores y usá GDB para:

1. Establecer un breakpoint en la función main
2. Ejecutar el programa paso a paso
3. Inspeccionar el valor de al menos tres variables en diferentes puntos
4. Documentar el flujo de ejecución
:label: ex-herramientas-3

Configurá VS Code con las tasks proporcionadas en esta guía. Verificá que podés:

1. Compilar con {kbd}`Ctrl+Shift+B`
2. Ejecutar Cppcheck desde el menú de tasks
3. Iniciar una sesión de debugging con {kbd}`F5`