so abändern, dass im weiteren Verlauf der Funktion LBA Teil einer Union
ist:
1
uniond_word{
2
unsignedlongintLBA;
3
struct{
4
unsignedcharbyte0;
5
unsignedcharbyte1;
6
unsignedcharbyte2;
7
unsignedcharbyte3;
8
};
9
};
Ist das direkt in der Funktionsdefinition möglich oder ist es sinnvoller
die Definition so zu belassen und innerhalb der Funktion die Union zu
definieren und dann den Wert hinein zu kopieren?
Danke im Voraus und schöne Grüße!
Simon B. schrieb:> Ist das direkt in der Funktionsdefinition möglich oder ist es sinnvoller> die Definition so zu belassen und innerhalb der Funktion die Union zu> definieren und dann den Wert hinein zu kopieren?
Nimm einen void Pointer als Parameter, damit kannst du per Casting
beliebig auf die Daten zugreifen.
Zu kopieren brauchst du dann nichts.
Hallo nochmal,
Ich hab das momentan wie von achs vorgeschlagen am Laufen; es
funktioniert, scheint mir allerdings vom Rechenaufwand für den µC
aufwändig. Macht aber momentan nichts, ist ein Hobby-Projekt. @achs: Ich
bin schon beruhigt, dass nicht nur ich das so sehe.
@joquis: Danke für die Stichworte, das dürfte so ungefähr das sein was
ich suche ;) Hier habe ich für die Zukunft einen Anhaltspunkt für meine
Weiterbildung.
Weitere Vorschläge sind natürlich willkommen, ich selbst mach für heute
Schluss, sonst wird's nix mit dem erholsamen Schlaf.
Schönen Abend euch allen!
A. S. schrieb:> Definition so lassen.>> Eine Union als Parameter ist meist suboptimal.
Bezüglich was?
Ob man eine Union mit der Größe und dem Alignment eines long int oder
ein long int an eine Funktion übergibt, ist einigermaßen Wurscht.
Ich jedenfalls schreibe üblicherweise, was ich meine und finde das
optimal ;)
Lothar M. schrieb:> Simon B. schrieb:>> scheint mir allerdings vom Rechenaufwand für den µC aufwändig.> Wie kommst du auf diesen Eindruck? Was ist da so langsam?
Naja, ich übergebe eine "große" Zahl an eine Funktion, die dann erst
einen neuen Speicherplatz dafür schafft und noch vier kleine dazugibt
mit denen ich dann weiterarbeiten kann. Und das jedes Mal wenn ich diese
Funktion aufrufe, was oft sein wird.
Mein Eindruck von Aufwändig entsteht dadurch, dass ich das Gefühl habe
einen Umweg zu programmieren. Ich weiß nicht im Detail wie der Compiler
das dann interpretiert bzw. optimiert, vermutlich macht er eh was
schlankes draus. Dass ich das aber nicht genau weiß macht mich irgendwie
nervös. Ist ein Persönlichkeitsding - ich hab die Dinge gern unter
Kontrolle, von da her wäre Assembler für mich perfekt, ich möchte aber
etwas mehr C-Praxis bekommen weshalb ich mein Unwohlsein bei der Sache
wohl akzeptieren muss.
Wenn das Programm dann mal läuft und ich Timing-Messungen daran machen
kann, werden sich vermutlich meine Bedenken in Luft auflösen. Bis dahin
werde ich betreffend dieses Themas etwas Unruhe verspüren ;)
So, nun aber gute Nacht - Danke euch allen!
Simon B. schrieb:> Naja, ich übergebe eine "große" Zahl an eine Funktion, die dann erst> einen neuen Speicherplatz dafür schafft und noch vier kleine dazugibt> mit denen ich dann weiterarbeiten kann.
Du weißt schon, was eine Union von einem Struct unterscheidet?
Markus F. schrieb:> Bezüglich was?
Eine Union ist in C relativ eingeschränkt. Ich kann ein Datum nur in der
Form rauslesen, wie ich's reingeschrieben habe.
Entweder der Up möchte immer ein Long übergeben, dann macht die Union
das ganze komplizierter als nötig.
Oder der Up möchte Mal ein Long, Mal ein struckt übergeben, dann lieber
ein void-ptr. Oder 2 Funktionen.
Eine Union nur dann, wenn diese Selbstzweck ist und nicht ihre Elemente.
Es ist wie ein goto, manchmal sinnvoll, aber meist schlechtes Design.
Eine Union als Parameter eigentlich nur als Teil eines structs, dessen
Inhalt u.a. beschreibt, welches Element gemeint ist (z.b. Telegramme)
Kümmer dich um Performance erst, wenn es (zu langsam) läuft.und dann mit
realem Cod hier. So wie es ausschaut, willst Du vielleicht
serialisieren und brauchst die Union vielleicht gar nicht. Zum lernen
ist es aber hinderlich vor jedem Schritt zu schauen, ob er auch perfekt
ist. Geh mit den Konstrukte, die Du kennst, bist Du sie so gut kennst,
dass Du (oder wir) sie verbessern können.
Eine union zu Verwenden um ein long in Bytes zu konvertieren o.ä. ist in
C Implementation defined (d.h. unportabel) und in C++ ganz verboten.
unions sind zum Speicher sparen gemacht, nicht zur Daten Konvertierung.
Es ist nicht ganz klar was jetzt bei dir der Fall ist. Mehr im Artikel
Serialisierung. Die genannte Möglichkeit Pointer zu casten ist
ebenfalls problematisch - nur in bestimmten Sonderfällen erlaubt, aber
auch dann unportabel. Möglicherweise ist es besser, mit bitweisen
Operationen zu arbeiten. Diese können auch gut vom Compiler optimiert
werden. Gerade wenn man C lernen will, sollte man sich direkt angewöhnen
wohldefinierten portablen Code zu schreiben. Optimierungen für
Sonderfälle kann man immer noch machen wenn es erwiesenermaßen (!) zu
langsam ist.
A. S. schrieb:> Definition so lassen.>> Eine Union als Parameter ist meist suboptimal.
Und am dritten Tag erschuf Gott den Pointer, um Funktionen beliebigen
Kram übergeben zu können.
Simon B. schrieb:> Ist das direkt in der Funktionsdefinition möglich oder ist es sinnvoller> die Definition so zu belassen und innerhalb der Funktion die Union zu> definieren und dann den Wert hinein zu kopieren?
Es ist sinnvoller, das mit der Union gleich ganz bleiben zu lassen.
Simon B. schrieb:> Naja, ich übergebe eine "große" Zahl an eine Funktion, die dann erst> einen neuen Speicherplatz dafür schafft und noch vier kleine dazugibt> mit denen ich dann weiterarbeiten kann. Und das jedes Mal wenn ich diese> Funktion aufrufe, was oft sein wird.
Das ist das, was Donald E. Knuth mit der Aussage "premature optimization
is the root of all evil" meinte. Es ist sehr wahrscheinlich, dass der
Compiler die Daten in Register kopiert, was er sowieso machen müsste, um
sie zu verarbeiten. Also Overhead: 0.
Wenn man mit der Programmierung anfängt, weiß man solche Details
natürlich nicht, sollte sich aber auch nicht darauf versteifen. Schreib
erstmal einfach dein Programm. Wenn es dann zu langsam sein sollte,
finde heraus, wo der Flaschenhals ist, dann optimiere gezielt diese
Stelle.
> Dass ich das aber nicht genau weiß macht mich irgendwie nervös. Ist ein> Persönlichkeitsding
Das geht vielen so, ist also ganz normal.
> Wenn das Programm dann mal läuft und ich Timing-Messungen daran machen> kann, werden sich vermutlich meine Bedenken in Luft auflösen. Bis dahin> werde ich betreffend dieses Themas etwas Unruhe verspüren ;)
So wird es sein.
jemand schrieb:> A. S. schrieb:>> Definition so lassen.>>>> Eine Union als Parameter ist meist suboptimal.>> Und am dritten Tag erschuf Gott den Pointer, um Funktionen beliebigen> Kram übergeben zu können.
Den Pointer hat er gleich am Anfang erschaffen. Aber void gab's erst am
dritten Tag. ;-)
Guten Morgen alle zusammen und danke für eure Rückmeldungen
A. S. schrieb:> So wie es ausschaut, willst Du vielleicht> serialisierenDr. Sommer schrieb:> Serialisierung
Genau das ist es was ich will, auf diesen Begriff wäre ich nie gekommen.
Danke für den Link, er wird mir weiterhelfen.
Markus F. schrieb:> Du weißt schon, was eine Union von einem Struct unterscheidet?
Ja. Definitiv.
A. S. schrieb:> Entweder der Up möchte immer ein Long übergeben [...]
Ja, so ist es. ich möchte einen Wert mit 32 Bit übergeben (LBA-Adresse)
und möchte diese in der Funktion per SPI ausgeben.
SPI-mäßig sehe ich zwei Möglichkeiten:
1: Startbyte ausgeben, Schnittstelle umstellen auf Übertragung von 4
bytes, LBA-Adresse als Long ausgeben, wieder rückstellen auf Byteweise
übertragung, Vorgang mittels Abschluss-Byte beenden.
2: Die LBA in einzelne Bytes aufteilen und einzeln schicken.
Ich habe mich für Variante 2 entschieden, weshalb ich also
"serialisieren" muss. Ich werde mich heute Abend mit dem Artikel
beschäftigen, aber jetzt ran an die Arbeit und schöne Grüße!
Rolf M. schrieb:> Den Pointer hat er gleich am Anfang erschaffen. Aber void gab's erst am> dritten Tag. ;-)
Ich bin bestimmt nicht bibelfest, aber ziemlich sicher, daß das Nichts
ganz am Anfang war ;)
Markus F. schrieb:> Ich bin bestimmt nicht bibelfest, aber ziemlich sicher, daß das Nichts> ganz am Anfang war ;)
Du meinst, er hat damit angefangen, nichts zu schaffen? Ich dachte, der
letzte Tag sei der Ruhetag gewesen, nicht der erste. ;-)
jemand schrieb:> Und am dritten Tag erschuf Gott den Pointer, um Funktionen beliebigen> Kram übergeben zu können.
Der T.O. hat es unten noch mal bestätigt, aber hat schon zu Anfang
geschrieben, dass er genau NICHT beliebige Sachen übergeben will. Ein
Pointer wäre damit genauso unsinnig wie die Union oder sonst eine
Verschleierungstaktik.
Wenn jemand immer ein Long übergeben will, dann ist ein Long in der
Schnittstelle auch das einzig sinnvolle.
A. S. schrieb:> geschrieben, dass er genau NICHT beliebige Sachen übergeben will. Ein> Pointer wäre damit genauso unsinnig wie die Union oder sonst eine> Verschleierungstaktik.
Pointer sind Verschleierungstaktik?
Beispiel:
1
typedef union{
2
//whatnot
3
}zeigstl;
4
5
void machwas(zeigstl *ptr){
6
//blabla
7
}
Da wird nichts verschleiert. Da ist genauestens definiert, was die
Funktion zu erwarten hat. Von dem Umstand mal abgesehen, dass Unions
ihre eigenen Probleme haben.
Nur kann man mit dem Prinzip Pointer beliebige Dinge übergeben.
A. S. schrieb:> Markus F. schrieb:>> Bezüglich was?>> Eine Union ist in C relativ eingeschränkt. Ich kann ein Datum nur in der> Form rauslesen, wie ich's reingeschrieben habe.
Da hab ich auch schon anderweitiges gelesen, zum Beispiel daß es seit
C99 offiziell erlaubt ist.
Mahzeit nochmal
A. S. schrieb im Beitrag #5630988:
> Wenn die Aufgabenstellung eine andere ist, z.B. dass die Union eh schon> beim Aufrufer vorliegt,
Darauf möchte ich noch kurz eingehen trotz der Befürchtung dass ich
damit vielleicht einigen Wirbel in die Diskussion bringe: Das Long das
ich an die Funktion übergeben möchte ist im Main bereits Teil einer
Union. Trotzdem möchte ich die Funktion auch z.B. mit
1
res=disk_read(0x11200,§or)
aufrufen können, was, wie ich denke, mit einer Pointervariante nicht
funktionieren wird.
Ich werde mir demnächst den Artikel zum serialisieren zu Gemüte führen
und die Übergabe eines Pointers auf das Union in der Main auch
ausprobieren. Dazu finde ich sicher Info im weltweiten Gewebe.
jemand schrieb:> Da wird nichts verschleiert. Da ist genauestens definiert, was die> Funktion zu erwarten hat. Von dem Umstand mal abgesehen, dass Unions> ihre eigenen Probleme haben.> Nur kann man mit dem Prinzip Pointer beliebige Dinge übergeben.
Der UP will immer ein Long übergeben. Alles andere als ein Long ist
daher suboptimal sprich: Verschleierung. Egal, ob es möglich, definiert
oder sonstwofür gut ist.
Bernd K. schrieb:> A. S. schrieb:>> Markus F. schrieb:>>> Bezüglich was?>>>> Eine Union ist in C relativ eingeschränkt. Ich kann ein Datum nur in der>> Form rauslesen, wie ich's reingeschrieben habe.>> Da hab ich auch schon anderweitiges gelesen, zum Beispiel daß es seit> C99 offiziell erlaubt ist.
Das ist bis auf eine Ausnahme falsch. C99 sagt:
"The value of at most one of the members can be stored in a union object
at any time."
Die Union kann immer nur eines seiner Members enthalten. Daraus folgt,
dass ich auch das lesen darf, das gerade enthalten ist.
Die Ausnahme:
"One special guarantee is made in order to simplify the use of unions:
if a union contains several structures that share a common initial
sequence (see below), and if the union object currently contains one of
these structures, it is permitted to inspect the common initial part of
any of them anywhere that a declaration of the complete type of the
union is visible."
Wenn ich also in einer Union zwei Strukturen habe, die gleich anfangen,
dann darf ich über eine der Strukturen den gemeinsamen Teil (und nur
den) lesen, auch wenn eigentlich die andere enthalten ist. Das ist die
einzige Situation, in der man ein anderes Element lesen darf als das,
das zuletzt reingeschrieben wurde.
Carl D. schrieb:> Oder vielleicht einfach so, wenn man nur innerhalb der Funktion> die> einzelnen Bytes verarbeiten will.unsigned char disk_read(unsigned long> int LBA, unsigned char *buf){> unsigned char* lba_bytes = (unsigned char*)&LBA;>> lba_bytes[0] = 0;>> }PS: ein ordentlicher Compiler verlangt dafür keinen Aufpreis.
Ein derartiger Zugriff per Pointer ist nicht zu empfehlen. Aus mehreren
Gründen:
a) Der Code ist abhängig von der Endianness
b) Man zwingt den Parameter oft auf den Stack
c) Auf einigen exotischen Plattformen mit Wortadressierung führt es
sogar zu undefiniertem Verhalten. Die implizierte Annahme, dass je
Adresse ein Byte vorliegt ist dort nämlich falsch. Ein 32-bit Wort
spannt meist über nur 2 Adressen, ein Array aus 4 Bytes aber über 4
Addressen. Folgendes wird dabei zum Knallfrosch:
x^2 schrieb:> c) Auf einigen exotischen Plattformen mit Wortadressierung führt es> sogar zu undefiniertem Verhalten.
Dann ist aber der Compiler kaputt, denn C schreibt vor, dass man jedes
beliebige Objekt als Array aus char interpretieren können muss.
> Die implizierte Annahme, dass je Adresse ein Byte vorliegt ist dort> nämlich falsch.
Das ist aber die Definition eines Bytes - die kleinste adressierbare
Einheit. Übrigens: Ein Byte muss in C nicht 8 Bit breit sein.
Rolf M. schrieb:> Das ist bis auf eine Ausnahme falsch. C99 sagt:>> "The value of at most one of the members can be stored in a union object> at any time."
In C11 ist das Lesen eines "anderen" union members plötzlich wieder
erlaubt - type punning über Unions ist explizit erwähnt. Wahrscheinlich
hat ein Commitee Member festgestellt, daß sie das selber benutzen.
Im gcc war es (als Erweiterung) meiner Kenntnis nach immer erlaubt.
Rolf M. schrieb:> Bernd K. schrieb:>> A. S. schrieb:>>> Markus F. schrieb:>>>> Bezüglich was?>>>>>> Eine Union ist in C relativ eingeschränkt. Ich kann ein Datum nur in der>>> Form rauslesen, wie ich's reingeschrieben habe.>>>> Da hab ich auch schon anderweitiges gelesen, zum Beispiel daß es seit>> C99 offiziell erlaubt ist.>> Das ist bis auf eine Ausnahme falsch. C99 sagt:>> "The value of at most one of the members can be stored in a union object> at any time."
Das ist ja wohl auch logisch da sie rein physikalisch nur Platz hat für
einen (den größten) member, das sagt aber absolut null aus zu obiger
Fragestellung. Hast also die falsche Stelle zitiert bzw. falsch
verstanden.
Ich zitiere jetzt auch mal aus dem Standard:
"If the member used to access the contents of a union object is not the
same as the member last used to store a value in the object, the
appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as described
in 6.2.6 (a process sometimes called "type punning"). This might be a
trap representation." - 6.5.2.3, fn 82 (Seite 73 unten)
Bernd K. schrieb:>> Das ist bis auf eine Ausnahme falsch. C99 sagt:>>>> "The value of at most one of the members can be stored in a union object>> at any time.">> Das ist ja wohl auch logisch da sie rein physikalisch nur Platz hat für> einen (den größten) member, das sagt aber absolut null aus zu obiger> Fragestellung.
Finde ich schon. Eine union ist wie eine Struct, nur dass eben zu jedem
Zeitpunkt nur eines der Elemente darin gespeichert sein kann. Es ist
dann eigentlich selbstverständlich, dass man dann auch nur das Element
lesen darf, das gerade gespeichert ist und kein anderes.
> Hast also die falsche Stelle zitiert bzw. falsch verstanden.>> Ich zitiere jetzt auch mal aus dem Standard:
Sicher, dass das C99 ist? In meinem C99 finde ich einen solchen Satz
nämlich nicht.
Rolf M. schrieb:> Eine union ist wie eine Struct
Nein.
— A structure type describes a sequentially allocated nonempty set of
member objects (and, in certain circumstances, an incomplete array),
each of which has an optionally specified name and possibly distinct
type.
— A union type describes an overlapping nonempty set of member
objects, each of which has an optionally specified name and possibly
distinct type.
Bernd K. schrieb:> Rolf M. schrieb:>> Eine union ist wie eine Struct>> Nein.
Toll abgeschnitten…
Bernd K. schrieb:> Rolf M. schrieb:>> meinem C99 finde ich einen solchen Satz>> nämlich nicht.>> Deiner ist zu alt.
Ok, dann wurde das nachträglich noch angepasst. Ich hatte in der
ursprünglichen Version ohne Korrekturen nachgeschaut.