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?
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.
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.
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.
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.
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.
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, ...
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.