8.5. Volatile

La sintaxis de volatile es idéntica a la de const, pero volatile significa «este dato puede cambiar sin que el compilador sea informado de ello». De algún modo, el entorno modifica el dato (posiblemente mediante multitarea, multihilo o interrupciones), y volatile indica la compilador que no haga suposiciones sobre el dato, especialmente durante la optimización.

Si el compilador dice, «yo guardé este dato en un registro anteriormente, y no he tocado ese registro», normalmente no necesitará leer el dato de nuevo desde memoria. Pero si esa variable es volatile, el compilador no debe hacer esa suposición porque el dato puede haber cambiado a causa de otro proceso, y debe releer el dato en vez de optimizar el código (dicha optimización consiste en eliminar la lectura redundante que se hace normalmente).

Pueden crearse objetos volatile usando la misma sintaxis que se usa para crear objetos constantes. También puede crearse objetos volatile constantes que no pueden cambiarse por el programador cliente pero se pueden modificar por una entidad ajena al programa. Aquí se muestra un ejemplo que representa una clase asociada con algún elemento físico de comunicación.

//: C08:Volatile.cpp
// The volatile keyword

class Comm {
  const volatile unsigned char byte;
  volatile unsigned char flag;
  enum { bufsize = 100 };
  unsigned char buf[bufsize];
  int index;
public:
  Comm();
  void isr() volatile;
  char read(int index) const;
};

Comm::Comm() : index(0), byte(0), flag(0) {}

// Only a demo; won't actually work
// as an interrupt service routine:
void Comm::isr() volatile {
  flag = 0;
  buf[index++] = byte;
  // Wrap to beginning of buffer:
  if(index >= bufsize) index = 0;
}

char Comm::read(int index) const {
  if(index < 0 || index >= bufsize)
    return 0;
  return buf[index];
}

int main() {
  volatile Comm Port;
  Port.isr(); // OK
//!  Port.read(0); // Error, read() not volatile
} ///:~

Listado 8.18. C08/Volatile.cpp


Como ocurre con const, se puede usar volatile para los atributos de la clase, los métodos y para los objetos en sí mismos. Sólo puede llamar a métodos volatile desde objetos volatile.

La razón por la que isr() no se puede usar como una rutina de servicio de interrupción (ISR) es que en un método, la dirección del objeto actual (this) debe pasarse secretamente, y una ISR no requiere argumentos. Para resolver este problema se puede hacer que el método isr() sea un método de clase (static), un asunto que se trata en el [FIXME:capitulo 10].

La sintaxis de volatile es idéntica a la de const, así que por eso se suelen tratar juntos. Cuando se usan combinados se conocen como cuantificador c-v (const-volatile).