1) In genere per evitare riferimenti circolari si usano forward reference (spesso dei puntatori), avendo poi l'accortezza di definire le varie funzioni solo dopo che tutti i tipi sono dati definiti.
Dovresti essere più specifico se hai un problema di questo tipo.

2) #pragma once è adottata solo da VC++ e dal nuovo Borland (a quanto ho letto). La via standard rimane di usare i vari define con le guardie di inclusione.

3) http://en.wikipedia.org/wiki/Opaque_pointer
Anche qui dovresti essere più specifico su quali dubbi hai. L'argomento è troppo per essere affrontato in poche righe.