Hallo,
ich schlag mich grad mal wieder mit einem Zeiger Problem herum.
Ich habe einen globalen Zeiger auf eine Struktur. Diese Struktur hat
unter anderem als Member einen Zeiger auf Daten:
1
typedefstruct{
2
//member;
3
//nochnmember;
4
uint8*data;
5
}my_struct_t;
6
7
my_struct_t*my_struct_ptr;
Nun würde ich gerne in einer Funktion auf den Datenteil dieser Struktur
zugreifen.
Folgendes funktioniert:
1
voidfoo(void)
2
{
3
uint8*local_ptr;
4
local_ptr=my_struct_ptr->data;
5
6
local_ptr[0]=...;
7
local_ptr[x]=...;
8
}
Probier ichs ohne Umweg über den lokalen Zeiger
1
my_struct_ptr->data[0]=...;
Meckert mirs der Compiler an.
"expression must be a pointer to a complete object type"
Damit kann ich nichts anfangen. Bin grad bisl ratlos, kann mir jemand
weiterhelfen?
Viele Grüße,
Rudi
>> Meckert mirs der Compiler an.> "expression must be a pointer to a complete object type"
der SChlüssel ist an dieser Stelle die Phrase "complete object type". An
der Stelle an der du das machst, weiß der Compiler nicht, wie ein
my_struct_t aussieht.
Wahrscheinlich hast du nur vergessen, das Header File zu inkludieren, in
dem die struct definiert ist.
Doch, die kennt er.
Allerdings hab ich mich getäuscht was den .data member betrifft.
Dieser ist vom Typ void* anstatt uint8*.
Aber das sollte doch keine Rolle spielen?
Rudi schrieb:> Dieser ist vom Typ void* anstatt uint8*.>> Aber das sollte doch keine Rolle spielen?
O doch, void-Pointer können nicht dereferenziert werden.
Hm garned bedacht. Macht aber Sinn, immerhin kennt er ja dann die Größe
des Elements nicht, sodass er spätestens beim Zugriff mitells [0],
[1]... überfordert wäre, richtig?
Rudi schrieb:> Hm garned bedacht. Macht aber Sinn, immerhin kennt er ja dann die Größe> des Elements nicht, sodass er spätestens beim Zugriff mitells [0],> [1]... überfordert wäre, richtig?
richtig.
In die Indexberechnung geht ja logischerweise auch immer die sizeof des
Typs ein um zu Berechnen, wieviele Bytes zwischen Anfang des Arrays und
dem interessierenden Arrayelement liegen.
Rudi schrieb:> Kann man das dann irgendwie umcasten?
natürlich kann man umcasten.
Allerdings solltest du dich fragen, ob da prinzipiell der void*
überhaupt eine gute Idee war. Wenn du sowieso den Datentyp kennst auf
den du casten willst, warum steht dann der nicht gleich da drinnen?
Es gibt natürlich Fälle, an denen man bewusst einen void* einsetzt. Zb
wenn ein Modul eine Strukturobjekt rausgeben muss und nicht haben will,
dass sich derjenige der das Objekt benutzt, an den Daten vergreift. Der
void* ist dann mehr oder weniger ein 'Finger weg! An diesen Daten hast
du nichts zu suchen'.
Weil der Typ von einer Lib, genauer gesagt dem LwIP Stack, vorgegeben
ist.
Dort gibt es die Struktur pbuf, die als Buffer für ein- und ausgehende
Datenströme dient. Und die zeigt leider auf void.
Wie müsste denn der Cast aussehen?
Rudi schrieb:> Weil der Typ von einer Lib, genauer gesagt dem LwIP Stack, vorgegeben> ist.>> Dort gibt es die Struktur pbuf, die als Buffer für ein- und ausgehende> Datenströme dient. Und die zeigt leider auf void.
Eigenartig.
Sicher, dass das so gedacht ist, dass du auf diese Werte zugreifen
darfst?
(Vielleicht wollten sie aber auch den Aufrufer auch nur dazu zwingen,
dass er ein wenig darüber nachdenkt, was das eigentlich für Daten sind,
die er da bekommt: int, float, double, bytes, ...
üblich ist es allerdings nicht. Solche Buffer werden normalerweise als
Bytes angesehen - also 'unsigned char' Arrays.
>> Wie müsste denn der Cast aussehen?
Na ja, eben den Pointer entsprechend umcasten
((uint8_t*)(my_struct_ptr->data))[0]
sieht ein wenig seltsam aus, daher wäre wohl der Weg über eine
Zwischenvariable der syntaktisch lesbarere. Der Compiler schmeisst die
Variable ja sowieso wieder raus.
Karl Heinz Buchegger schrieb:> Eigenartig.> Sicher, dass das so gedacht ist, dass du auf diese Werte zugreifen> darfst?
Laut der (leider sehr dürftigen) Doku im Internet und den Beispielen die
ich gefunden habe wird das durchaus so gemacht.
Die allokierte Buffergröße wird auch in der Struktur abgelegt, somit ist
es wohl dem Benutzer überlassen den Zugriff ordentlich zu regeln.
Aber ich muss sagen, der LwIP Stack ist nicht gerade ein Musterbeispiel
für lesbaren Code...
Rudi schrieb:> Karl Heinz Buchegger schrieb:>> Eigenartig.>> Sicher, dass das so gedacht ist, dass du auf diese Werte zugreifen>> darfst?>> Laut der (leider sehr dürftigen) Doku im Internet und den Beispielen die> ich gefunden habe wird das durchaus so gemacht.>> Die allokierte Buffergröße wird auch in der Struktur abgelegt, somit ist> es wohl dem Benutzer überlassen den Zugriff ordentlich zu regeln.
:-)
Womit sich dann allerdings die Frage erhebt, wie denn die Buffergröße
angegeben ist. Sind das Bytes, Floats, andere Objektgrößen, Äpfel,
Birnen ...
:-)
(Ist jetzt keine Kritik an dir. Soll dir nur zeigen, dass an dieser
Stelle der void* nicht sehr logisch ist. WEnn ich schon die Buffergröße
(in Bytes) in der Struktur habe, dann wäre es logisch auch den Pointer
als Byte-Pointer anzulegen. Dann passen beide in den Einheiten zusammen.
Ändert nichts daran, dass man des öfteren sowieso umcasten muss. Aber
dann muss man ja auch die Längenangabe umrechnen und kann das so gesehen
ohnehin nicht verpassen.
Das Ganze ist wohl einfach "historisch gewachsen" und generell sehr
undurchsichtig.
Die Puffer sind außerdem einfach verkettet und speichern noch ihr
nächstes Element, die Gesamtgröße der Kette und die Größe des jeweiligen
Segments. Alle Angaben in Bytes.
Und halt das Datenelement als void*.
Aber das geht ja noch, richtig dreckig sind erst die Präprozessor
Spielereien...
Karl Heinz Buchegger schrieb:> (Ist jetzt keine Kritik an dir. Soll dir nur zeigen, dass an dieser> Stelle der void* nicht sehr logisch ist.
Warum nicht? Ist auch nicht anders, als auf dem PC. Wenn ich da mit
read() aus einem Socket lese, übergebe ich auch einen void* und einen
size_t, was er dann nutzt, um seine Daten reinzuschreiben.
Es geht um einen Puffer mit (für das API) völlig unbekanntem Inhalt. Da
erscheint mir ein void* eigentlich recht passend. malloc() gibt ja auch
keinen Zeiger auf char zurück, nur weil ich ihm als Parameter die
gewünschte Größe in Bytes angebe.