Forum: Compiler & IDEs Circular include Problem


von Martin (Gast)


Lesenswert?

Hallo, ich habe ein kleines Problem und finde auf die Schnelle keine 
Lösung.

event.h

typedef uint32_t EventMaskType;

StatusType SetEvent ( TaskType TaskID, EventMaskType Mask );



task.h

typedef uint32_t TaskType;
typedef enum
{
  xxx,
yyy
}TaskStateType;

typedef struct
{
  TaskStateType TaskState;
  EventMaskType ActiveEvents;
}OsekOsTaskType;


Jetzt brauche ich in event.h einen Include auf task.h wegen dem 
TaskType.
In der task.h brauche ich aber die event.h wegen dem EventMaskType.

Damit würden sie sich gegenseitig includieren. Dass kann ich zwar mit 
#ifndef und so lösen, aber dann findet der Compiler die Typen teilweise 
nicht.

Habt ihr eine Idee?

von Peter (Gast)


Lesenswert?

- Alles in einen Header
- Die typedefs in einen dritten Header
- Die typedefs duplizieren

von W.S. (Gast)


Lesenswert?

Ja, natürlich.

Du brauchst bloß deine unsinnigen Typumwandlungen ersatzlos 
wegzustreichen:

typedef uint32_t EventMaskType;
typedef uint32_t TaskType;

Verrate doch mal der Allgemeinheit, WOZU du diese Verrenkungen 
eigentlich machst. Im Grunde brauchst du durchweg nix anderes als 
unsigned long für all deine Events.

Mein Eindruck ist, daß du "a la mode" programmierst, also ohne 
Systematik das hinschreibst, was grad Mode ist.

W.S.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Peter schrieb:
> - Alles in einen Header
> - Die typedefs in einen dritten Header
> - Die typedefs duplizieren

- Die Deklaration von SetEvent von event.h nach task.h verschieben, wo
  sie ohnehin besser aufgehoben ist, da die Funktion dazu dient, das
  Verhalten eines Tasks zu beeinflussen

Gibt es Fälle, wo du in einer .c-Datei nur event.h oder nur task.h
includen würdest, oder würdest du immer beide zusammen includen? Wenn
letzteres der Fall ist, dann würde ich beide Headers zu einem einzigen
zusammenschmeißen und diesen task.h nennen.

W.S. schrieb:
> Du brauchst bloß deine unsinnigen Typumwandlungen ersatzlos
> wegzustreichen:
>
> typedef uint32_t EventMaskType;
> typedef uint32_t TaskType;

Diese Typsynonyme sind schon sinnvoll, da es nicht naturgegeben ist,
dass die Anzahl der Events >16 und ≤32 ist, weswegen man sich nicht für
alle Zeiten auf einen bestimmten Integer-Typ festlegen möchte. Durch
den Typedef ist der Typ auch zukünftig noch leicht änderbar. Ähnliches
gilt auch für den Task-Typ.

: Bearbeitet durch Moderator
von W.S. (Gast)


Lesenswert?

Yalu X. schrieb:
> Diese Typsynonyme sind schon sinnvoll, da es nicht naturgegeben ist,
> dass die Anzahl der Events >16 und ≤32 ist, weswegen man sich nicht für
> alle Zeiten auf einen bestimmten Integer-Typ festlegen möchte.

Da knurrt aber bei mir der Blindenhund..

Also, du hast auch keine Erklärung für einen "EventMaskType" und einen 
"TaskType", wobei dies mit irgend welchen Typsynonymen garnichts zu tun 
hat.

Anstelle irgendwelcher Event-Maskentypen oder dergleichen sollte der TO 
lieber eine ordentliche Systematik in den definierten Events schaffen.

Ich geb dir mal ein Beispiel:
1
/*
2
Ein Event wird durch ein dword (32bit) dargestellt.
3
Davon
4
die untersten 4 Bit     (0..3)   sind die Event-Gruppe,
5
die nächsthöheren 8 Bit (4..11)  sind Event-ID's innerhalb der Gruppe
6
die übrigen 20 Bits     (12.. 31) sind Zusatz-Informationen
7
*/
8
9
#define evGruppenMaske  0x00F
10
#define evEventMaske    0xFFF
11
12
/*
13
Hier:
14
  0 = nix, Event gelöscht
15
  1 = Hardware-Events  (von Treibern gesendet)
16
  2 = Tastatur-Events  (Tasten gedrückt oder losgelassen)
17
  3 = Maus-Events      (Position und Tasten)
18
  4 = Menü-Events      (menüinterner Broadcast, für menü-interne Organisation)
19
  5 = Timer-Events     (Zeitsignale, Botschaften, etc.)
20
  6 = Org-Events       (Organisation und Broadcast aus dem Betriebssystem)
21
  7 = Sensor-Events    (hier: Positionssensoren)
22
  8 = Error-Events     (alles, was mit Fehlern zu tun hat)
23
  9..14 noch undefiniert
24
 15 = App-Events       (anwendungsspezifisches Zeugs)
25
*/
26
27
/* die Gruppen-Id's */
28
#define idHard    1
29
#define idTast    2
30
#define idMaus    3
31
#define idMenu    4
32
#define idTimer   5
33
#define idOrg     6
34
#define idSensor  7
35
#define idError   8
36
#define idApp    15
37
38
39
/* Gruppe 1 = Hardware-ID's */
40
#define idDrehL       ((1<<4)  | idHard)
41
#define idDrehR       ((2<<4)  | idHard)
42
#define idDrehT       ((3<<4)  | idHard)
43
#define idLTast       ((4<<4)  | idHard)
44
#define idRTast       ((5<<4)  | idHard)
45
#define idIrAvail     ((10<<4) | idHard)
46
#define idNotHalt     ((11<<4) | idHard)
47
48
49
/* Gruppe 2 = Tasten-ID's   */
50
#define idKbMake      ((0<<4) | idTast)
51
#define idKbBreak     ((1<<4) | idTast)
52
/* hierbei: Bit 16..31 ist der WideChar dazu */
53
#define idEnterTaste  ((2<<4) | idTast)
54
#define idLinksTaste  ((3<<4) | idTast)
55
#define idRechtsTaste ((4<<4) | idTast)
56
#define idRaufTaste   ((5<<4) | idTast)
57
#define idRunterTaste ((6<<4) | idTast)
58
#define idEscapeTaste ((7<<4) | idTast)
59
60
#define idTaste0      ((8<<4)  | idTast)
61
#define idTaste1      ((9<<4)  | idTast)
62
#define idTaste2      ((10<<4) | idTast)
63
#define idTaste3      ((11<<4) | idTast)
64
#define idTaste4      ((12<<4) | idTast)
65
#define idTaste5      ((13<<4) | idTast)
66
#define idTaste6      ((14<<4) | idTast)
67
#define idTaste7      ((15<<4) | idTast)
68
#define idTaste8      ((16<<4) | idTast)
69
#define idTaste9      ((17<<4) | idTast)  /* usw. je nach Bedarf */

Sowas ist auf einem 32 Bit Controller durchaus passend. Man könnte aber 
auch einen Event als struct definieren, dann wäre dort mehr Platz für 
Interna und Werte mit dabei, siehe Eventverwaltung bei Windows.

Auf alle Fälle braucht man keine albernen EventMaskType's, sondern 
stattdessen eine Headerdatei, wo die entscheidenden KENNWERTE eines 
Events wie im Beispiel zentral definiert sind. Also nochmal zum 
Mitschreiben: zentral nicht Typen definieren, sondern Inhalte 
definieren.

Schließlich ist der Knackpunkt ja der, daß das Generieren eines Events, 
dessen Verwaltung (Warteschlange) und dessen Verwertung (Reaktion auf 
ihn) in ganz unterschiedlichen Programmteilen erfolgt.

Das ist ja eben der tiefere Sinn dahinter. Also müssen diese eine 
zentrale Stelle haben, wo die Inhalte festgelegt sind, aber keine 
Typdefs's.
Hast du das jetzt?

W.S.

von Yalu X. (yalu) (Moderator)


Lesenswert?

W.S. schrieb:
> Ich geb dir mal ein Beispiel:
> ...
> Man könnte aber auch einen Event als struct definieren

Das ist ja alles schön und gut, geht aber IMHO an dem, was der TE
vorhat, komplett vorbei. Das, was du beschreibst, hat Ähnlichkeit mit
dem Event-System in GUI-Frameworks. Das, woran der TE gerade arbeitet,
liegt aber vermutlich mehrere Ebenen tiefer, so ungefähr auf Scheduler-
Ebene eines Betriebssystems oder Echtzeitkernels.

Für mich sieht es eher so aus:

Es laufen mehrere Tasks, von denen jeder über eine Task-ID identifiziert
wird. Diese Task-ID ist einfach eine Integer-Zahl. Um sich nicht für
alle Zeiten auf einen bestimmten Wertebereich festlegen zu müssen, hat
der TE dafür einen neuen Typnamen definiert.

Jeder Task kann auf verschiedene Events reagieren. Diese werden jeweils
durch 1 Bit in einer Integer-Zahl repräsentiert. Das Strukturelement
ActiveEvents ist entweder die Menge der durch den Task zu bearbeitenden
oder die Menge der für den Task freigeschalteten Events. Falls letzteres
der Fall sein sollte, wäre allerdings EnabledEvents als Name passender.
Dadurch, dass die Eventbits alle in einer einzelnen Integer-Variablen
stehen, kann durch Bit-Operationen sehr schnell ermittelt werden, ob ein
bestimmtes Event gerade aktiv oder freigeschaltet ist. Da die Anzahl
verschiedener Events evtl. noch nicht endgültig feststeht, hat der TE
auch hier einen neuen Typnamen definiert.

Es kann natürlich sein, dass ich mich irre. Deswegen lassen wir am
besten Martin wieder zu Wort kommen.

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Auf alle Fälle braucht man keine albernen EventMaskType's, sondern
> stattdessen eine Headerdatei, wo die entscheidenden KENNWERTE eines
> Events wie im Beispiel zentral definiert sind.

Man braucht eine Headerdatei, in der sowohl der Typ, als auch die Werte 
definiert sind. Was will ich denn mit den schön sauber definierten 
Werten, wenn ich mir den passenden Typ bei jeder Verwendung nochmal neu 
ausdenken muss?

> Schließlich ist der Knackpunkt ja der, daß das Generieren eines Events,
> dessen Verwaltung (Warteschlange) und dessen Verwertung (Reaktion auf
> ihn) in ganz unterschiedlichen Programmteilen erfolgt.

Ja eben. Und wenn ich den Typ mal ändern muss, hab ich keine Lust, an X 
Stellen nachschauen zu müssen, ob der dort gerade verwendete Typ 
zufällig noch passt. Ich will es an genau einer Stelle im Programm 
anpassen können.
Dafür sind Typedefs da, und sie nicht dafür zu verwenden, ist grober 
Unfug.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:

> Ja eben. Und wenn ich den Typ mal ändern muss, hab ich keine Lust, an X
> Stellen nachschauen zu müssen, ob der dort gerade verwendete Typ
> zufällig noch passt. Ich will es an genau einer Stelle im Programm
> anpassen können.
> Dafür sind Typedefs da, und sie nicht dafür zu verwenden, ist grober
> Unfug.

Manche leben halt in einer int-Welt ... dort gibts auch kein size_t, ...

von Wilhelm M. (wimalopaan)


Lesenswert?

W.S. schrieb:

> Sowas ist auf einem 32 Bit Controller durchaus passend. Man könnte aber
> auch einen Event als struct definieren, dann wäre dort mehr Platz für
> Interna und Werte mit dabei, siehe Eventverwaltung bei Windows.

Das sollte man auf jeden Fall tun. Denn ein Event ist nun mal kein int!

Solange ich typedef (das ist ja nur ein typ-alias und keine 
Typ-Defintion) verwende, kann ich einen Event implizit in einen anderen 
ganzzahligen Typen konvertieren. Ich kann also jede Funktion mit einem 
ganzzahligen Parameter mit einem Event aufrufen. Das ist sicher nicht 
sinnvoll! Auch C hat ein Typsystem, was man nutzen kann.
1
typedef uint32_t Event_t;
2
3
uint32_t foo(uint16_t x) {
4
    return 2 * x;
5
}
6
7
struct EventSafe {
8
    uint32_t value;
9
};
10
11
int main() {
12
    Event_t e1 = 1;
13
    foo(e1); // Quatsch
14
    
15
    EventSafe e2 = {2};
16
//    foo(e2); // geht so nicht -> gut!
17
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.