Hallo zusammen,
ich habe zwei structs. Der Typ des einen structs liegt fest - ich kann
ihn nicht ändern. Den Typ des zweiten Structs kann ich frei festlegen.
Ich will einen Zeiger auf einen dieser beiden Structs durch den Inhalt
unterscheidbar machen.
Im C-Quelltext also ungefähr so:
1
// Struct mit unveraenderlicher Struktur
2
typedefstructfixedstruct_s
3
{
4
uint8_t*a;
5
intsomeweirdcontent;
6
uint8_tb,c,d;
7
}
8
Fixedstruct_t;
9
10
// Struct frei waehlbarer Struktur (solange alles hineinpasst)
11
typedefstruct
12
{
13
uint8_t*null;
14
uint32_tlala;
15
uint16_tlili;
16
uint16_tlulu;
17
}
18
StructOfFreeChoice_t;
19
20
typedefstruct
21
{
22
uint8_t*discriminator;
23
}
24
Genericstruct_t;
25
26
27
28
booldiscriminateStructPointer(void*S)
29
{
30
Genericstruct_t*G=(Genericstruct_t*)S;
31
if(G->discriminator==NULL)
32
return1;
33
else
34
return0;
35
}
36
37
38
/* Funktion zum Testen von Sachen. */
39
intmain(void)
40
{
41
uint8_tsomethingToPointTo;
42
Fixedstruct_tA={.a=&somethingToPointTo};// Rest nicht initialisiert
43
StructOfFreeChoice_tB={.null=NULL,};// Wird bei Typ A nie vorkommen
44
45
46
inta=discriminateStructPointer(&A);
47
intb=discriminateStructPointer(&B);
48
printf("typeA=%i, typeB=%i",a,b);
49
50
returnEXIT_SUCCESS;
51
}
Das Beispiel läuft.
Ich finde im C-Standard nichts zur Dereferenzierung eines void-Zeigers
auf einen unpassenden struct-Typ. Deshalb die Frage:
- Ist diese Methode zulässig?
- Oder gibt es eine bessere Methode?
Viele Grüße
W.T.
Dr. Sommer schrieb:> Typischerweise macht man so etwas als "Tagged Union
Könnte ich beide structs ändern, machte ich es so. Das eine struct ist
allerdings unveränderlich.
Du hast mindestens an zwei Stellen undefined behaviour.
-Du dereferenzierst einen NULL-Pointer.
-Du greifst auf ein Objekt über einen nicht zulässigen Typ zu (strict
aliasing rule).
Ohne dein fixedstruct_t zu "verändern", wird es nicht gehen. Es gibt nen
Grund warum C++ nen vptr braucht.
Dr. Sommer schrieb:> Dann packe es so wie es ist in die Tagged Union hinein.
Ginge dieser einfache Weg, ginge ich ihn.
mh schrieb:> -Du dereferenzierst einen NULL-Pointer.
Wo?
mh schrieb:> -Du greifst auf ein Objekt über einen nicht zulässigen Typ zu (strict> aliasing rule).
Das ist implementation defined, aber ja: Das ist der Knackpunkt. Ich
suche eine saubere Unterscheidung. Gerne auch auf eine komplett andere
Art und Weise.
Walter T. schrieb:> mh schrieb:>> -Du dereferenzierst einen NULL-Pointer.>> Wo?
1
StructOfFreeChoice_tB={.null=NULL,};
2
intb=discriminateStructPointer(&B);
3
booldiscriminateStructPointer(void*S)
4
Genericstruct_t*G=(Genericstruct_t*)S;
5
if(G->discriminator==NULL)
Walter T. schrieb:> mh schrieb:>> -Du greifst auf ein Objekt über einen nicht zulässigen Typ zu (strict>> aliasing rule).>> Das ist implementation defined, aber ja: Das ist der Knackpunkt. Ich> suche eine saubere Unterscheidung.
Nein es ist undefined.
mh schrieb:> Walter T. schrieb:>> mh schrieb:>>> -Du dereferenzierst einen NULL-Pointer.>>>> Wo?StructOfFreeChoice_t B = {.null = NULL,};> int b = discriminateStructPointer(&B);> bool discriminateStructPointer(void *S)> Genericstruct_t *G = (Genericstruct_t *) S;> if( G->discriminator == NULL )
Ok das war unsinn von mir.
So, ich habe es. Nicht schön, aber sollte gehen: Ich kann mir magische
Zahlen für den Inhalt von "Fixedstruct_t" ausdenken, die bei einem
echten Struct nie vorkommen könnten. Wenn ich mein zweit-Struct
entsprechend konstruiere, dass jeder Datentyp gleich ist, sollte auch
keine Alias-Regel verletzt werden.
Deine "Lösung" mit Magics gefällt mir überhaupt nicht.
Warum übergibst Du Deiner Funktion discriminateStructPointer(void *S)
nicht einfach einen 2. Parameter is_fixed, in welchem notiert ist, um
welche Struct es sich handelt? Die aufrufende Funktion weiß das doch!
Wenn diese das jedoch auch nicht weiß, weil Du den Pointer über mehrere
Funktionsebenen heruntergibst, dann machs so:
1
typedefstruct
2
{
3
union
4
{
5
Fixedstruct_tFixed;
6
Piggyback_tPiggyback;
7
}u;
8
intis_fixed;
9
}
10
Genericstruct_t;
Dann kannt Du die Information, um welche struct es sich handelt, direkt
in den Daten mitschleppen. Das funktioniert auch noch, wenn Du später
die eine oder andere Structs erweiterst und Deine Magics dadurch auch
mal fehlinterpretiert werden könnten.
mh schrieb:> -Du greifst auf ein Objekt über einen nicht zulässigen Typ zu (strict> aliasing rule).
Ja, das gute alte strict aliasing. Zum Glück kann man diese unnütze
Elfenbeinturm-Regel bei allen gängigen Compilern ausschalten, dann
erzeugt er den Code den man hinschreibt, so wie es eigentlich von Anfang
an hätte sein sollen.