Ámbitos con el Pre compilador, 3ª parte, definir bien el cuándo

Se puede con el precompilador crear una especie de ámbito del cuando.

En programación, un buen programador intenta separar los 5 momentos clave, o ámbitos de ejecución.

  • Qué
  • Cuándo
  • Dónde
  • Cómo
  • Por qué

No siempre se logra, de hecho, con el precompilador puedes lograr separar algunos, pero el más complicado o el que da más problemas es:

Cuándo

Para controlar el cuándo se incluye dentro de tu programa unas instrucciones, te puedes ayudar el precompilador.

Habrás visto que una práctica muy común en las librerías es construirlas de esta manera:

#ifndef TALPALABRA
#define TALPALABRA

           <----- montones de cosas ------>
#endif

Es la mejor manera de hacer una librería.

Veamos qué hace:

  • Verifica que la palabra TALPALABRA NO EXISTE
  • Se abre un ámbito de cuándo para el precompilador
  • La define para que ya esté disponible
  • Declara o hace lo que tiene que hacer, se genera o declara el cómo
  • Se indica #endif, y se cierra el ámbito del cuándo.

Entonces, cuando tu incluyes la librería, si la palabra TALPALABRA no existe, porque nunca pasó por la instrucción

#define TALPALABRA

Se incluye toda la librería, la cual, bien realizada, debería indicar sólo cómo deben hacerse las cosas (tal función hace esto, tal función hace esto otro, tal variable global es definida de aquí en adelante, etc…)

Si tu haces include varias veces de la misma librería, por ejemplo porque usas una librería de servos, pero la librería de servos también es incluida por otra librería que tu incluiste, que no has hecho tu, pero que también la usa, o cualquier otra circunstancia…

Ocurre que el #ifndef te ayuda mucho, porque sólo permite que se declaren esas funciones una vez, así se evita que por accidente declares dos veces la misma función o la misma variable global, y en ese caso el compilador, ahora el compilador no el precompilador, no sabe qué hacer, y te va a dar un error, diciendo que ya está definido y que intentas definirlo otra vez.

#include <Arduino.h>

void funcionRepetida() {}
void funcionRepetida() {}

void setup() {}
void loop() {}

Este es el mensaje que da:

AmbitoSencillo:3:6: error: ‘void funcionRepetida()’ previously defined here
void funcionRepetida() {}
^

Si incluyo una librería dos veces me pasaría eso, y si incluyo dos librerías que hacen diferentes cosas pero con el mismo nombre, es decir funcionRepetida(), y las necesito, con namespaces ya sabemos controlarlo.

#include <Arduino.h>

namespace veznecesaria1{
    void funcionRepetida() {}
}

namespace veznecesaria2{
    void funcionRepetida() {}
}
void funcionRepetida() {}

void setup() {
    veznecesaria1::funcionRepetida();
    veznecesaria2::funcionRepetida();
    funcionRepetida();
}
void loop() {}

Ahora la hemos podido incluir 3 veces, para que no no dé problemas, porque son distintas, única razón para utilizar el namespace, sin embargo, con el precompilador, el juego es el siguiente:

#include <Arduino.h>

#ifndef TALPALABRA
#define TALPALABRA
void funcionRepetida() {}
#endif

#ifndef TALPALABRA
#define TALPALABRA
void funcionRepetida() {}
#endif

#ifndef TALPALABRA
#define TALPALABRA
void funcionRepetida() {}
#endif


void setup() {
    funcionRepetida();
}
void loop() {}

Ahora se nos ha declarado, o intentado declarar 3 veces la misma función que, supongamos hace la misma cosa, por eso no uso namespaces, sino precompliador, y ya la tengo una sola vez para todo el programa.

Lo que pasa es que cuando haces muchos includes no sabes o conoces el ámbito de cuándo se incluye, por eso es bueno separar el qué (la librería sólo dice como hacer) del cuándo.

Mira como se puede o aconseja hacer un sketch:

// --- Librerías del sistema primero
#include <Arduino.h>

// --- Librerías de terceros
#include <libreríaDeTerceroQueHaceIncludeDeServo.h>

// --- Mis propias librerías donde sólo digo cómo se resuelve algo
#include "milibreria.h"

void setup() {
    llamoafuncion();    // --- Y aquí declaro cuándo se resuelve
}
void loop() {}

De esta manera, si en tu librería “milibreria.h” incluías la librería servo.h, no hay conflicto, porque si está bien hecha la librería libreríaDeTerceroQueHaceIncludeDeServo.h tendrá instrucciones ifndef y define para contener el error.

Tú también deberías construir tus librerías con esa contención. Quizás creas que no, porque nunca te vas a equivocar y son tuyas. Consejo:

Nunca menosprecies tu capacidad de cometer errores, haz caso a alguien que ya ha menospreciado demasiadas veces su propia capacidad de cometerlos.