Forum: Mikrocontroller und Digitale Elektronik Was passiert hier: #define Addr (*(uint16_t*)&com[2])


von Bastian (Gast)


Lesenswert?

Hallo Leute,

mir ist nicht 100%ig klar, was hier passiert:
1
void Command( unit8_t com[] ) {
2
  
3
  #define Addr (*(uint16_t*)&com[2]) // Was passiert hier genau?
4
5
  ...
6
7
}

Der Funktion Command wird ein uint8_t-Array mit 8 Elementen übergeben.

Soll dann die Adresse des dritten Array-Elementes als 16 Bit Pointer 
interpretiert werden, ähnlich wie hier?
http://www.proggen.org/doku.php?id=c:cast#vorsicht_beim_casten1

Was bedeutet der erste Stern?

Danke im Voraus!

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> Was bedeutet der erste Stern?

Dass du ein C Handbuch brauchst. ;-)

Der linke Stern dereferenziert, der rechte macht einen Pointer aus dem 
Typ im Cast.

von Bastian (Gast)


Lesenswert?

Oh, ich glaube jetzt hat es geschnackelt!

Mit dem ersten * greife ich ja auf den Inhalt des neu gecasteten 
16bit-Pointers zu und damit auf Byte 3 und 4 des Arrays als 16bit-Zahl?!

von (prx) A. K. (prx)


Lesenswert?

Richtig. Nicht empfehleswert bei Prozessoren mit alignment restrictions.

von Bastian (Gast)


Lesenswert?

A. K. schrieb:
> Dass du ein C Handbuch brauchst. ;-)

Bin dabei, bin dabei. Aber du verstehst sich, das für einen Anfänger so 
ein Ausdruck erst einmal schwierig ist. An was man sich da alles 
erinnern muss ;-)

von Bastian (Gast)


Lesenswert?

Oh nein

A. K. schrieb:
> Richtig. Nicht empfehleswert bei Prozessoren mit alignment restrictions.

Oh nein, schon wieder was zum nachlesen ;-)

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> Aber du verstehst sich, das für einen Anfänger so
> ein Ausdruck erst einmal schwierig ist.

Yep. C ist nichts für Ästheten, und sowas schon garnicht.

Bastian schrieb:
> Oh nein, schon wieder was zum nachlesen ;-)

Aber das findest du im C Handbuch nicht.

von Extrem Entzückter (Gast)


Lesenswert?

>#define Addr (*(uint16_t*)&com[2])

Super -so eine einfache und klare Struktur! Da erkennt man auf den 
ersten
Blick, wofür das gut ist.....

(Der Beitrag kann geringe Spuren von Ironie enthalten)

Warum tut sich ein Mensch solchen Rotz an?
Das ist Masochismus in Reinkultur.

von Bastian (Gast)


Lesenswert?

A. K. schrieb:
> Aber das findest du im C Handbuch nicht.

Dachte ich mir, wohl eher im µC Datenblatt?!

von Tom (Gast)


Lesenswert?

1
#include <stdio.h>
2
#include <inttypes.h>
3
4
void Command( uint8_t com[] ) {
5
    #define Addr (*(uint16_t*)&com[2]) // Was passiert hier genau?
6
    printf("0x%x\n", Addr);
7
}
8
9
int main(void)
10
{
11
    uint8_t foo[] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
12
    Command(foo);
13
    return 0;
14
}

Von rechts nach links lesen:
com         Ist hier foo
[2]         Das 3. Element von foo.
&           davon die Adresse nehmen und ...
(uint16_t*) ... als Zeiger auf einen uint16_t ansehen (der
                bei 0x33 beginnt und 2 Byte groß ist)
*           ... und diesen dereferenzieren.
=> Ergebnis 0x4433

Wie man sieht, ist mein PC Little Endian, weil "das kleinstwertige Byte 
an der Anfangsadresse gespeichert [wird]".

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> Dachte ich mir, wohl eher im µC Datenblatt?!

In der Beschreibung des Prozessors. Wenn es nicht grad ein 8-Bit Typ 
ist, denn denen ist das üblicherweise egal.

von Bastian (Gast)


Lesenswert?

Extrem Entzückter schrieb:
> Warum tut sich ein Mensch solchen Rotz an?
> Das ist Masochismus in Reinkultur.

Dann wirst du das lieben:
1
s = (*(uint16_t*)&com[4]) | ((*(uint16_t*)&com[2])<<16);

.

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> Dann wirst du das lieben:

Lass dann aber die überflüssigen Klammern und Leerzeichen weg! ;-)
1
s = *(uint16_t*)&com[4]|*(uint16_t*)&com[2]<<16;
Nur APL ist schöner:
1
life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

von Georg G. (df2au)


Angehängte Dateien:

Lesenswert?

Extrem Entzückter schrieb:
> Das ist Masochismus in Reinkultur.

Du bis aber leicht zu beeindrucken. Schau mal hier rein: 
http://www.ioccc.org/

Eines der harmloseren Beispiele als Anhang. Das Programm tut durchaus 
etwas sinnvolles und wird von einem (BSD) C-Compiler sauber übersetzt.

von Bastian (Gast)


Lesenswert?

A. K. schrieb:
> s = *(uint16_t*)&com[4]|*(uint16_t*)&com[2]<<16;

Macht
1
(uint16_t*)&com[2]<<16

nicht alles zu Null?

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> nicht alles zu Null?

Weshalb? Präfix Operatoren wie *, & und Cast haben Vorrang vor <<, und 
der wiederum vor |. Einzig die Klammern vom Cast sind als integraler 
Teil ebendieses Operator unverzichtbar.

von Bastian (Gast)


Lesenswert?

A. K. schrieb:
> Weshalb? Präfix Operatoren wie * und Cast haben Vorrang vor <<.

Ich meinte, wenn ich eine 16bit-Zahl um 16 Stellen nach links 
verschiebe.

Ich dachte die "neuen" Stellen werden mit Nullen aufgefüllt!?

von Wegstabenverbuchsler (Gast)


Lesenswert?

Extrem Entzückter schrieb:
> Warum tut sich ein Mensch solchen Rotz an?
> Das ist Masochismus in Reinkultur.

Du scheinst "bessere" Programmiersprachen zu kennenn. Welches wäre denn 
deine bevorzugte Programmier-Sprache, welche automatisch (oder mit 
entsprechenden Befehl) selbiges auf die gegebene Datenstruktur ausführt?

Könntest du das mal aus Ausdruck hinschreiben? Dann könnten wir mal 
ästhetische Vergleiche durchführen.

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> Ich dachte die "neuen" Stellen werden mit Nullen aufgefüllt!?

Und? Ok, auf einem 8/16-Bitter wird es wirklich zu 0, aber das hat 
nichts mit den Klammern zu tun. Das Statement stammt offensichtlich aus 
einer 32- oder 64-Bit Umgebung.

von Bastian (Gast)


Lesenswert?

A. K. schrieb:
> Und? Ok, auf einem 8/16-Bitter wird es wirklich zu 0, aber das hat
> nichts mit den Klammern zu tun.

Ja, das meint ich. Was das woll soll?

von (prx) A. K. (prx)


Lesenswert?

Bastian schrieb:
> Ja, das meint ich. Was das woll soll?

Das soll heissen, dass nicht jeder Code, der für einen 32-Bit Prozessor 
geschrieben wurde, auch auf einem 16-Bitter läuft.

von Extrem Entzückter (Gast)


Lesenswert?

Wegstabenverbuchsler
>Du scheinst "bessere" Programmiersprachen zu kennenn.

Naja -zumindest welche, für deren Syntaxübersetzung einer Zeile nicht
Stunden und mehrere C-Bücher braucht. Das sieht man ja hier gerade,
wie die obige Zeile von mehreren Leuten jeweils anders interpretiert 
wird.

>Welches wäre denn
>deine bevorzugte Programmier-Sprache,

früher Pascal heute Lazarus oder Pure-Basic

>welche automatisch (oder mit
>entsprechenden Befehl) selbiges auf die gegebene Datenstruktur ausführt?

weiß ich nicht -so eine Konstruktion habe ich noch nie gebraucht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bastian schrieb:
> Ich meinte, wenn ich eine 16bit-Zahl um 16 Stellen nach links
> verschiebe.
>
> Ich dachte die "neuen" Stellen werden mit Nullen aufgefüllt!?

Nein, zumindest nicht wenn sizeof(int) = 2 ist.  Dann ist's undefined 
behaviour (oder unspecified? die werf ich immer durcheinander).

von Mark B. (markbrandis)


Lesenswert?

Georg G. schrieb:
> Extrem Entzückter schrieb:
>> Das ist Masochismus in Reinkultur.
>
> Du bis aber leicht zu beeindrucken. Schau mal hier rein:
> http://www.ioccc.org/
>
> Eines der harmloseren Beispiele als Anhang. Das Programm tut durchaus
> etwas sinnvolles und wird von einem (BSD) C-Compiler sauber übersetzt.

Wir sind uns hoffentlich über zwei Dinge einig:

1.) Der IOCCC bringt schon ein paar geile Dinge hervor (ich mag 
besonders die Sachen von Oscar Toledo).
2.) Niemand, der noch ganz bei Trost ist, programmiert so in einem 
Industrieprojekt in dem es darum geht Geld zu verdienen.

Wegstabenverbuchsler schrieb:
> Du scheinst "bessere" Programmiersprachen zu kennenn.

Nein, das ist keine Frage der Programmiersprache. Das hier gezeigte 
Code-Beispiel ist aus verschiedenen Gründen (z.B. Prozessorabhängigkeit, 
Lesbarkeit, Wartbarkeit) einfach grottig. Man kann in jeder Sprache 
schlechten Code schreiben, auch und gerade in C. Das heißt aber nicht, 
dass man es auch tun sollte.

> Welches wäre denn
> deine bevorzugte Programmier-Sprache, welche automatisch (oder mit
> entsprechenden Befehl) selbiges auf die gegebene Datenstruktur ausführt?

Code wird immer noch nach Anforderungen entwickelt. Die richtige Frage 
lautet daher: Was ist eine sinnvolle Anforderung, die bei sauberer 
Programmierung zu einem Code-Beispiel wie dem oben gezeigten führt?

Und schon wird die Luft ganz dünn. ;-)

von Falk S. (falkschilling)


Lesenswert?

Mark Brandis schrieb:
> 2.) Niemand, der noch ganz bei Trost ist, programmiert so in einem
> Industrieprojekt in dem es darum geht Geld zu verdienen.

So wie im IOCCC sicher nicht, das bedient ja auch eher die künstlerische 
Ader. Das Beispiel des Threaderöffners schockiert mich ehrlich gesagt 
nicht mal im Ansatz - dazu wühlt man sich durch zuviel C/C++-Code und 
hat häufig nicht den Zeitrahmen, das sauberer z.B. über Unions zu lösen. 
Gerade bei einer großen Codebasis kommst du dann beim Refactoren vom 
Hundersten ins Tausendste.

> Wegstabenverbuchsler schrieb:
>> Du scheinst "bessere" Programmiersprachen zu kennenn.
>
> Nein, das ist keine Frage der Programmiersprache. Das hier gezeigte
> Code-Beispiel ist aus verschiedenen Gründen (z.B. Prozessorabhängigkeit,
> Lesbarkeit, Wartbarkeit) einfach grottig. Man kann in jeder Sprache
> schlechten Code schreiben, auch und gerade in C. Das heißt aber nicht,
> dass man es auch tun sollte.

Glaube ich nur begrenzt. Ich behaupte, dass die Designer einer 
Programmiersprache sehr wohl und sehr deutlich durch die Grammatik den 
Programmierstil der Programmierer beinflussen! Eine moderne Sprache 
stellt sich sicher auf die Mehrzahl ihrer Programmierer ein und schließt 
alleine durch ihre Sprachgrammatik bereits Fehler aus.

Beispiel: die notwendige Implementierung von virtuellen Destruktoren in 
rein virtuellen (abstrakten) Klassen bei C++ ist so ein Fehler, der mich 
so einige Memleaks in der Vergangenheit gekostet hat - bloß weil der 
Compiler einen automatischen nicht-virtuellen Destruktor für das 
Interface gebaut hat und somit der Destruktor der Ableitung nicht 
aufgerufen wurde... macht Java oder C-Gartenzaun (C#) mittels eigenem 
Schlüsselwort besser.

>> Welches wäre denn
>> deine bevorzugte Programmier-Sprache, welche automatisch (oder mit
>> entsprechenden Befehl) selbiges auf die gegebene Datenstruktur ausführt?
>
> Code wird immer noch nach Anforderungen entwickelt. Die richtige Frage
> lautet daher: Was ist eine sinnvolle Anforderung, die bei sauberer
> Programmierung zu einem Code-Beispiel wie dem oben gezeigten führt?
>
> Und schon wird die Luft ganz dünn. ;-)

Nicht immer ist eine Anforderung, dass der Code lesbar ist. Gerade bei 
Schnittstellen, deren interne Funktion nicht leicht ertestbar sein 
sollen, entsteht mitunter übler Code. Oder aber wenn ein Feature schon 
vorgestern fertig sein musste, der Programmierer aber erst heute davon 
erfährt... :)

Weiteres Beispiel: Constraints! Wenn du also jemanden hast, der dir 
keine Requirements spezifiziert, sondern praktisch das Design vorgibt 
(z.B. durch Fremdcode), an den du dich halten musst, so sind das 
Constraints für dich.
Und dann argumentier mal bitte von wegen Qualitäten usw. wenn das 
Projekt seitens des Herstellers höchstens noch Wartungsaufwand generiert 
und daher nur die gröbsten Bugs gefixt werden...

Und die ultimative Antwort auf Frage nach der Anforderung, die solchen 
Code generiert: nicht '42', sondern das kleine, unscheinbare Wort 
'Termindruck'...

von Mark B. (markbrandis)


Lesenswert?

Sicher, wenn eine Firma mit schlechtem Code leben will, der soll sie 
dies tun. Dann soll sie sich aber auch gefälligst nicht beschweren, wenn 
das Ergänzen von neuer Funktionalität länger dauert und somit teurer 
ist.

von Falk S. (falkschilling)


Lesenswert?

Mark Brandis schrieb:
> Sicher, wenn eine Firma mit schlechtem Code leben will, der soll
> sie dies tun. Dann soll sie sich aber auch gefälligst nicht beschweren,
> wenn das Ergänzen von neuer Funktionalität länger dauert und somit teurer
> ist.

Na, dann erzeugen neue Funktionen neue Aufwände und die kann man 
bekanntlich besser abrechnen... man wundert sich dann aber später darum, 
warum die Zeitschätzungen für neue Projekte immer vollkommen (deutlich > 
Faktor 2) daneben liegen...

Das Lustige daran: in der Janus-köpfigen Firmenwelt ist doch die 
Time-To-Market oft das entscheidende Merkmal. Nach draußen groß auf 
Qualität machen, aber dem Softwareentwickler nicht wirklich die Zeit 
geben, wirklich eine qualitativ hochwertige Codebasis zu schaffen (z.B 
wegen irgendwelcher anderen Projekte). Diesen Luxus hat man nicht immer. 
Da schreibste halt erstmal so, dass es überhaupt funktioniert, bis du 
irgendwann mal Zeit findest, das ordentlich zu machen.

Weitere Behauptung von mir: Programmierer, die nie ranzigen Code 
geschrieben haben, warten bzw. erweitern oder auch nur verstehen 
mussten, sollten sich sehr glücklich schätzen... denn es gibt immer 
Code, der noch schlechter ist...

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> Dann ist's undefined behaviour
> (oder unspecified? die werf ich immer durcheinander).

Undefined. Ist auch besser so, denn verschiedene Implementierungen der 
gleichen Architektur verhalten sich dabei u.U. unterschiedlich.

von Georg G. (df2au)


Lesenswert?

A. K. schrieb:
> Undefined.

Darf ich widersprechen? K&R, Seite 189, Linkshift: "vacated bits are 
0-filled", Rightshift: 0-fill wenn unsigned, nur bei signed ist es 
undefiniert (0 oder das Vorzeichenbit).

Wäre es wirklich immer undefiniert, würden Bitoperationen wie "x |= (1 
<< BITPOS) nicht funktionieren. Und die findet man ja wohl zu hauf.

von Karl H. (kbuchegg)


Lesenswert?

Georg G. schrieb:
> A. K. schrieb:
>> Undefined.
>
> Darf ich widersprechen? K&R, Seite 189, Linkshift: "vacated bits are
> 0-filled", Rightshift: 0-fill wenn unsigned, nur bei signed ist es
> undefiniert (0 oder das Vorzeichenbit).

Darum gehts nicht.
Es geht darum, was passieren soll, wenn man um mehr Bits shifted, als 
der Datentyp groß ist.
Und das ist undefined. Ich kann mich an einen Fall erinnern, in dem das 
links Shiften eines 16 Bit Wertes um 16 Bits zu keiner Veränderung des 
Wertes geführt hat.

von (prx) A. K. (prx)


Lesenswert?

Georg G. schrieb:
> Darf ich widersprechen?

Nein. Es ging um die Frage, was bei N >= #Bits passiert.

Da arbeitete beispielsweise der 8086 noch Modulo 256, die Nachfolger 
aber Modulo 32 (bzw. 64 bei 64-Bit Operationen). Bei N=33 gibts also 
recht verschiedene Ergebnisse.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Schilling schrieb:
> nicht den Zeitrahmen, das sauberer z.B. über Unions zu lösen.

Union ist ohnehin kaum „sauberer“.

Sauber wäre es, mit einer Inline-Funktion die Bytes einzeln zu
schieben und zu addieren (oder zu verODERn).

Für den hier genannten Zweck (das Rauspopeln der Adresse aus dem
Bytehaufen erfolgt ja nur für ein printf(), also zu Debugzwecken)
ist das ein pragmatischer Ansatz, den man durchaus wählen kann.
Es fehlt eigentlich nur ein
1
#undef Addr
 direkt nach der
Benutzung, damit niemand auf die Idee käme, den Makro anderweitig
zu missbrauchen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.