In un appunto precedente avevo già parlato della parola chiave const; ritorno brevemente sull'argomento per evidenziare il suo utilizzo con le variabili puntatori.

Qual'è la differenza tra const Obj* p e Obj* const p?

const Obj* p significa che lo stato dell'oggetto Obj non potrà essere modificato tramite il puntatore p; questo però non implica che lo stato dell'oggetto sia necessariamente costante nel tempo. Supponiamo ad esempio che Obj sia definito come segue:

class Obj
{
  void inspect() const; // Non modifica lo stato di Obj
  void mutate(); // Modifica lo stato di Obj
};

La funzione main() evidenzia cosa è permesso e cosa non è possibile con il puntatore const Obj* p.

int main()
{
  Obj o;
  const Obj* p = &o;
  Obj* q = &o;

  p->inspect(); // OK: p non modifica l'oggetto.
  p->mutate(); // Errore: p non può modificare l'oggetto.

  q->inspect(); // OK: q può ispezionare l'oggetto
  q->mutate(); // OK: q può modificare lo stato dell'oggetto

  f.inspect(); // OK: f può ispezionare l'oggetto
  f.mutate(); // OK: f può modificare lo stato dell'oggetto

  ...
}

Come si vede nel'esempio precedente, il puntatore p non può essere utilizzato per modificare lo stato di dell'oggetto o, mentre q non è soggetto ad alcuna restrizione. 

Obj *const p indica che p è un puntatore costante ad un oggetto di tipo Obj, il che significa che è possibile modificare l'oggetto puntato tramite p, ma non è possibile modificare il puntatore stesso.


Quando la CPU rileva un segnale di interrupt, libera il bus dati ed abilita il dispositivo in attesa ad inviare l'interrupt vector. Un interrupt vector è l'indirizzo di memoria di un interrupt handler (la routine di gestione dell'interrupt), o un indice in un array chiamato interrupt vector table o dispatch table. Una Interrupt vector table contiene gli indirizzi di memoria degli interrupt handler.

Dopo la generazione di un interrupt, il processore salva il suo stato di esecuzione ed avvia l'esecuzione dell' interrupt handler corrispondente all'interrupt vector.


Gli eventi di VxWorks sono un meccanismo di comunicazione tra task e interrupt routine (ISR), tra task ed altri task o task e oggetti VxWorks. Gli oggetti VxWorks sono definiti anche risorse e includono i semafori e le code di messaggi. Gli eventi possono essere inviati dai task, dalle ISR e dalle risorse, mentre possono essere ricevuti solo dai task.

Affinché un task possa ricevere un evento è necessario che si registri sulla risorsa e affinché una risorsa possa inviare un evento è indispensabile che sia libera. Gli eventi assomigliano ai segnali, nel senso che solo i task registrati possono ricevere un evento da una particolare risorsa, ma al contrario di quello che succede con i segnali, uno stesso task può essere registrato per ricevere gli eventi di più risorse: uno stesso task può attendere che un determinato semaforo diventi libero e che un messaggio arrivi in una particolare coda di messaggi.

Un'altra differenza degli eventi rispetto ai segnali consiste nel fatto che sono sincroni: un task in attesa di un particolare evento rimane bloccato finché l'evento non si verifica, ma una volta che l'evento è stato ricevuto il task prosegue la propria esecuzione.

Un task può rimanere in attesa anche di un evento che non è collegato ad una risorsa specifica, ma semplicemente inviato da un altro task o da una ISR: in questo caso non è necessario che il task si registri per la ricezione dell'evento, ma è sufficiente che chi lo invia conosca qual'è il task interessato a riceverlo.

Infine due task non possono registrarsi per ricevere un evento da una medesima risorsa: la registrazione del secondo task comporta o la restituzione di un errore o la de-registrazione automatica del primo task.


Per scrivere una funzione C++ compatibile con il compilatore C è necessario informare il compilatore C++ della nostra intenzione, utilizzando la parola chiave extern come specificato di seguito.

 

// Questo è un file C++

// Dichiarare func(int,char,float) utilizzando extern "C":
extern "C" void func(int i, char c, float x);

...

// Definire f(int,char,float) in qualche modulo C++:
void f(int i, char c, float x)
{
...
}

Fondamentalmente la linea extern "C" dice al linker di utilizzare le convenzioni di chiamata del C. Attenzione che l'overloading delle funzioni non è supportata!


Per includere all'interno di un file C++ un file header scritto in C è necessario racchiudere la direttiva di inclusione all'interno del costrutto extern "C" { /* ... */}; in questo modo è possibile informare il compilatore C++ che le funzioni dichiarate nel file header sono funzioni C. Supponiamo di voler utilizzare all'interno di un file C++ la funzione C func(int i, char c, float x), la cui dichiarazione è contenuta nel file header denominato "Codice_C", allora nel codice C++ dovremmo scrivere:

// Questo è un file C++

extern "C" {
  #include "Codice_C.h"
}

int main()
{
  func(7, 'x', 3.14);
  ...
}

E' bene notare che la chiamata della funzione è identica a quella che si avrebbe in un file C.

Si può ottenere lo stesso risultato anche modificando il file header, aggiungendo al suo interno le opportune direttive.

/* Questo è un file header C */

#ifdef __cplusplus
  extern "C" {
#endif

/* Corpo del file header */

#ifdef __cplusplus
  }
#endif

Poiché il simbolo __cplusplus è definito solo se si utilizza un compilatore C++, questa tecnica rende compatile un file header C con i file C++.


Calendario

<<  febbraio 2012  >>
lumamegivesado
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar

Archivio

Licenza d'uso
Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati mediante:

Licenza Creative Common