Herranz

Sesión 11: “Módulos”

¿Recuerdas el ejercicio del LCG? ¿El generador de números aleatorio (generador congruencial lineal)? Vamos a retomarlo y vamos a ver cómo se modulariza un programa en C paso a paso.

Programa sin módulos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <stddef.h>

/* Park-Miller */
#define A 16807LU
#define C 0LU
#define M 2147483647LU

/*
 * Variable con el siguiente número aleatorio,
 * se inicializa con la semilla
 */
long unsigned int x = 12345LU;

/* Función de generación: LCG */
unsigned long int generar_aleatorio() {
  unsigned long int aleatorio = x;
  x = (A * x + C) % M;
  return aleatorio;
}

/*
 * Convención entre los programadores de C:
 * se pasa la longitud del array en otro parámetro
 */
unsigned long int media(unsigned long int a[], size_t n) {
  size_t i;
  unsigned long int sum = 0;
  for (i = 0; i < n; i++) {
    /* CUIDADO: cierto riesgo de overflow */
    sum += a[i]; 
  }
  return sum / n;
}

/* Array donde almacenaremos N números del generador */
#define N 1000000
unsigned long int aleatorio[N];

int main() {
  int i;

  for (i = 0; i < N; i++)
    aleatorio[i] = generar_aleatorio();

  for (i = 0; i < N; i++)
    printf("%lu\n", aleatorio[i]);

  printf("\n%lu\n", media(aleatorio, N));
  
  return 0;
}

“Header” público y “C” privado

Estructura de directorios

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
CC = gcc
CFLAGS = -Wall -Wextra -Werror -ansi
IFLAGS = -Iheaders
SRC_DIR = src
OBJ_DIR = obj
EXE = generar

# Archivos fuente y objeto
SRCS = $(wildcard $(SRC_DIR)/*.c)
OBJS = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRCS))

# Regla principal
all: $(EXE)

# Regla para enlazar el ejecutable
$(EXE): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

# Regla para compilar cada archivo .c en un .o
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
	$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $@

# Reglas de limpieza
clean:
	rm -f $(OBJ_DIR)/*.o

veryclean: clean
	rm -f $(EXE)

# Regla para crear directorios necesarios si no están creados
prepare:
	mkdir -p $(OBJ_DIR)

# Lista de reglas que no generan ficheros
.PHONY: all clean prepare

¿Qué ponemos en un header?

1
 extern unsigned long int x;
1
 unsigned long int media(unsigned long int *a, size_t n);
1
2
3
4
5
6
7
8
#ifndef MEDIALU_H
#define MEDIALU_H

#include<stddef.h>

extern unsigned long int media(unsigned long int *a, size_t n);

#endif /* medialu.h incluido. */

¿Cuál es la media del generador para el primer millón de datos?

1
 $ ./generar | tail