hi
hat jemand eine gute idee für folgendes Problem:
Ich habe eine standard sendefunktion die ich aber nur 1x aufrufen darf.
Diese erwartet einen Pointer auf den Datenanfang und eine entsprechende
Länge.
1
voidfoo(uint8_t*ptr,uint32_tlen)
Nun möchte ich vor dem senden der Daten noch einen Header einbauen.
Kann aber weder vorher speicher reservieren noch den pointer der daten
verschieben.
bisher wird der datenbereich komplett kopiert.
1
voidbar(uint8_t*ptr,uint32_tlen)
2
{
3
uint8_t*buf=malloc(len+20);
4
5
// header in neuen buffer und kopieren der daten
6
uint32_tnew_len=make_header(buf,ptr,len);
7
8
foo(buf,new_len);
9
10
free(buf);
11
}
gibt es eine elegante lösung um den extra buffer zu vermeiden ?
bzw das kopieren zu vermeiden?
quasi eine insertfunktion am anfang des buffers
53453453454353 schrieb:> quasi eine insertfunktion am anfang des buffers
Das liefe auf ein Verschieben des Pufferinhalts hinaus, und das ist
nicht effizienter, als den Pufferinhalt zu kopieren.
Nein, gibt es nicht. Typische Workarounds sind
- Sendefunktion mit head und data, je ptr und len.
- Sendefunktion mit oder ohne Abschluss (write und write_line)
- konkrete Headerbehandlung in angepasster Sendefunktion
danke ...
dachte vieleicht habe ich etwas übersehen.
Aber es scheint wohl die die einzige lösung zu sein solange man die
sendefunktion nicht umbiegen kann.
Diese kann ich leider nicht umbauen ohne die ganze Lib dahinter zu
zerreißen.
53453453454353 schrieb:> ohne die ganze Lib dahinter zu zerreißen.
Wenn die Strings nicht im ROM sind, kannst Du es auch auf der
aufruferseie lösen, indem sie vorne Platz für de Header haben.
Auch stört es manchmal nicht, eine Funktion (bzw. ein File) zu überladen
hi
dasgeht leider nicht weil der string aus einer Lib kommt wo ich wieder
nichts ändern will/darf
die funktion hat einen pointer als returnwert
das ist dann auch der stringanfang
Wenn du keine Möglichkeit hast, den Speicher vor dem String zu benutzen
(wer weiß, was deine Lib da speichert) und du auch keine Möglichkeit
hast, Header und Daten getrennt zu senden, dann wirst du um eine Kopie
nicht herumkommen. Punkt.
Peter D. schrieb:> memmove() kann ein Array verschieben.
wenn dahinter platz ist , ja
da ich aber nur einen pointer habe und nicht weiß wieviel platz hinter
dem string ist , kann ich das nicht verschieben ohne gefahr zu laufen
den heap kaputt zu machen
der string kommt aus einer lib die ich nicht allein unter kontrolle habe
deswegen bleibt nur die kopiererei
53453453454353 schrieb:> der string kommt aus einer lib die ich nicht allein unter kontrolle habe
Das ist unüblich, dann muß der Aufrufer den String ja wieder freigeben.
Üblich ist, der Aufrufer reserviert den Platz und übergibt den Pointer
darauf. Dann muß der Aufrufer auch nicht malloc bemühen, sondern legt
einfach ein lokales Array an.
Peter D. schrieb:> Das ist unüblich, dann muß der Aufrufer den String ja wieder freigeben.> Üblich ist, der Aufrufer reserviert den Platz und übergibt den Pointer> darauf. Dann muß der Aufrufer auch nicht malloc bemühen, sondern legt> einfach ein lokales Array an.
ist leider so.
in dieser Lib wird mit malloc speicher geholt.
Je nach stringlänge unterschiedlich groß
Ich bekomme entweder NULL oder einen gültigen pointer zurück
Wenn NULL sende ich nichts und gebe auch nichts frei.
Wenn gültig muss ichd as senden und entwprechend wieder freigeben.
Ich habe aber die möglichkeit beim senden zu entscheiden ob ich das
gesammte Paket senden will oder nur teile.
Aktuell war immer das gesamte paket im sendepuffer.
Ich werde das mal testen in dem ich es aufteile und dann versende.
so brauch ich nicht noch einen großen buffer allozieren sondern nur
einen kleinen den ich neu füllen muss bis das paket weg ist.
53453453454353 schrieb:> in dieser Lib wird mit malloc speicher geholt.> Je nach stringlänge unterschiedlich groß
Ich weiß eigentlich nie, wie groß ein String letztendlich wird. D.h. ich
alloziere immer die mögliche Maximalgröße und schreibe dort den String
rein.
Rufus Τ. F. schrieb:> Sofern das ganze nicht irrwitzig zeit- und speicherkritisch ist,> kannst> Du Dein Problem mit einer Kombination aus realloc und memmove lösen.
nunja richtig kritisch nicht.
ist halt ein/mehrere IP Pakete
macht realloc aber nicht genau das?
er holt einen größeren block ( stringlänge + zusatz )
copiert die daten in den neuen und dann Free( alter block )
rückgabewert ist ein neuer pointer des neuen blocks
dieses neue holen einen größeren blocks will ich ja vermeiden :-)
das mache ich ja gerade aktuell ...
ich hole einen neuen block( header + stringlänge )
setze den header und copiere den string rein
dann kann ich den alten block mit string freigeben.
Ich MUSS ja aber zur Laufzeit 2 blöcke aktiv haben
Peter D. schrieb:> 53453453454353 schrieb:>> in dieser Lib wird mit malloc speicher geholt.>> Je nach stringlänge unterschiedlich groß>> Ich weiß eigentlich nie, wie groß ein String letztendlich wird. D.h. ich> alloziere immer die mögliche Maximalgröße und schreibe dort den String> rein.
Das ist momentan eine künstliche Grenze bei 8Kb
und das mache ich momentan ja so.
Möchte das aber bei bedarf nur so groß machen wie nötig.
bzw nicht doppelt belegen.
na ich seh schon ...
so richtig elegant ohne die Libs zu bearbeiten kommt man nicht
drumherum.
Einzig das paketweise versenden kann mir noch helfen.
( Websocket mit FIN bit )
53453453454353 schrieb:> dieses neue holen einen größeren blocks will ich ja vermeiden :-)
Realloc holt nicht zwingend einen neuen Block, das tut es nur, wenn sich
der vorhandene nicht vergrößern lässt.
Warum willst Du das zwanghaft vermeiden? Aus Überzeugung?
Wenn die Rahmenbedingungen so sind, wie von Dir geschildert, /geht es
nicht anders/.
Rufus Τ. F. schrieb:> Warum willst Du das zwanghaft vermeiden? Aus Überzeugung?
eher aus dem grunde:
aktuell sind es um 4-5kb maximal
es kann aber auch anwachsen
also momentan 4-5Kb als string als returnwert der funktion
dazu ein neuer buffer mit platz für den header nochmal 4-5kb
zum senden ...
temporär sind das 10kb platz
wenn die daten nun doch noch ansteigen ist es sinnvoll nur die hälfte zu
verbrauchen
Wenn Du da ein Problem siehst, rede mit denjenigen, die die beiden
beiligten Libraries gebastelt haben, auf daß sie das Verhalten ändern.
Geht das nicht, dann geht das nicht, und Du musst halt den Speicher
entsprechend verarbeiten. Auf was für einem System läuft das, daß Du Dir
um 10 kB Sorgen machst?
ich verstehe die Konstrukte mit memmove und realloc nicht. Der String
der Reinkommt kann damit nicht bearbeitet werden, der zwischenpuffer
(per malloc geholt) braucht es nicht.
Zu malloc an sich: malloc kann einen segmentierten Speicher
hinterlassen. Es stellt sich daher m.E. die Frage, ob hier nicht
vielleicht doch die Maximalgröße auf dem Stack oder statisch allokiert
werden sollte.
Statisch natürlich nur, wenn diese Funktion niemals aus verschiedenen
Tasks aufgerufen werden kann.
Auf dem Stack natürlich nur, wenn dieser dafür entsprechende vergrößert
wird.
Die saubere Lösung ist natürlich immer noch, die eine Sendefunktion der
Lib um ein Datenfeld zu ergänzen oder in 2 oder 3 aufzuteilen.
SendeStart(void *data, int len); SendeAppendEnd(void *data, int len);
Dann braucht es kein malloc, keine Kopiererei.
Achim S. schrieb:> ich verstehe die Konstrukte mit memmove und realloc nicht. Der String> der Reinkommt kann damit nicht bearbeitet werden, der zwischenpuffer> (per malloc geholt) braucht es nicht.
Da der "String der reinkommt" mit malloc angefordert wurde, kann auf
diesen String realloc angewandt werden, um den Puffer zu vergrößern, und
dann mit memmove der Inhalt so verschoben werden, daß die
davorzusetzenden Daten halt davor passen.
Wenn die Rahmenbedingungen so sind, daß weder die Routine, die die
Eingangsdaten liefert noch die Senderoutine geändert werden kann, ist
das so ziemlich die einzig mögliche Vorgehensweise.
Wenn die Rahmenbedingungen beschreiben würden, daß die Puffergröße ein
bestimmtes Maximum nicht überschreiten kann, und wenn die
Rahmenbedingungen ausreichend Platz auf dem Stack vorsehen würden,
könnte man auch wie von Dir vorgeschlagen den Kram als automatisches
Array maximaler Größe auf den Stack packen, aber es wird beschrieben,
daß die im Moment ca. 5 kByte Puffergröße wohl auch noch (irgendwie?)
wachsen können.
Kann man sich also wohl auch nicht drauf verlassen.
Daß bei Einsatz von malloc & Co. Fragmentierungsprobleme auftreten
können, ist klar, aber das kann bei den beknackten Rahmenbedingungen
nicht umgangen werden. Obendrein enthalten die Rahmenbedingungen selbst
bereits den Einsatz von malloc & Co., da hilft es vermutlich nur wenig,
hier darauf zu verzichten.
Fazit:
Beknackte Rahmenbedingungen sind beknackte Rahmenbedinungen. Und
schlechte APIs sind schlechte APIs.
Rufus Τ. F. schrieb:> Da der "String der reinkommt" mit malloc angefordert wurde, kann auf> diesen String realloc angewandt werden, um den Puffer zu vergrößern, und> dann mit memmove der Inhalt so verschoben werden, daß die> davorzusetzenden Daten halt davor passen.
Naja, falls Du diese Aussage des UP meinst:
53453453454353 schrieb:> ist leider so.> in dieser Lib wird mit malloc speicher geholt.> Je nach stringlänge unterschiedlich groß
Das habe ich eher als allgemeine Beschreibung gesehen und nicht zwingend
auf den Anfang des Strings bezogen. Und selbst wenn, wäre ein
realloc/memmove hier sehr gefährlich und nicht sonderlich performant:
a) es unterstellt, dass der Aufrufer seinen eigenen String nicht mehr
benutzen darf (er ist vollkommen zerstört)
b) es unterstellt, dass der String beim Aufrufer immer am Anfang des
Malloc-Bereichs liegt.
c) wenn der Original-Bereich zu klein ist, wird der String zweimal
kopiert.
Und selbst dann muss die Library geändert werden, da der Aufrufer den
Speicherbereich für seinen bisherigen String nicht mehr freigeben darf
!!
sorry das ich hier so eine lange diskusion ausgelöst habe ^^
die Libs sind leider nicht von mir und teilweise sogar fremde open
source libs die ich nicht ändern will
der andere Teil die diese lib verwendet ist von kollegen ...
Ändere ich irgendwas schränkt das die wiederverwendbarkeit auf anderen
Geräten ein.
Wäre es ein hobbyprojekt würde sich die frage garnicht stellen und ich
hätte das einfach umgebaut.
Ich dachte nur es gibt vlt eine möglichkeit soetwas elegant zu lösen
ohne einen noch größeren speicher zusätzlich zu verwenden.
abgesehen vom eigenmächtigen Ändern ... oder das senden der daten in
mehreren chunks bleibt keine möglichkeit.
Ich danke nochmal allen beteiligten für die hinweise/hilfe