Forum: Mikrocontroller und Digitale Elektronik AVR GCC - Adresse von Variable nach Typecast


von André W. (sefiroth)


Lesenswert?

Hallo,

ich habe eine Funktion, welche die Adresse einer Char-Variable erwartet. 
Die Daten die ich ihr übergeben möchte liegen in einer "volatile 
uint8_t"-Variable.

Gibt es eine Möglichkeit direkt beim Funktionsaufruf die uint8_t 
Variable mittels typecast in eine Char-Variable zu wandeln, und davon 
die Adresse zu übergeben?

Momentan mache ich es über diesen Umweg:
1
volatile uint8_t u8_USB_Keyboard_Ascii_Data;   // Wird im Interrupt gefüllt
2
3
void usb_write_character(char* value);
4
5
int main (void)
6
{
7
...
8
9
char Data = u8_USB_Keyboard_Ascii_Data;
10
usb_write_character( &Data );
11
12
...
13
}

Ich finde es aber unelegant dafür extra die Data-Variable anzulegen.

Gruß,
André

von Michael R. (dj_motionx)


Lesenswert?

Was sagen die Experten zu:
1
usb_write_character( &( (char)u8_USB_Keyboard_Ascii_Data );

L.g.

von Karl H. (kbuchegg)


Lesenswert?

1
  usb_write_character( (char*)&u8_USB_Keyboard_Ascii_Data);


Wobei etwas einen Programmierer sofort stutzig machen sollte:
Warum nimmt eine Funktion, die EINEN Character ausgeben soll, überhaupt 
einen Pointer auf diesen Character?

Darauf gibt es keine vernünftige Erklärung und auch keinen vernünftigen 
Grund. Ganz im Gegenteil. Alles spricht dafür genau so etwas nicht zu 
tun und den Character einfach nur als Character zu übergeben. Man 
arbeitet nicht mittels Pointer, wenn man nicht muss. Und hier muss man 
nicht.

Die Chancen stehen gut, dass diese Funktion eben keinen einzelnen 
Character ausgibt, sondern einen String. Denn in diesem Fall würde man 
in der Funktionsschnittstelle dann tatsächlich einen char* erwarten. 
Entweder das, oder der Programmierer dieser Funktion war ein 
vollkommener und totaler Anfänger.


In deinem "Problem", auf das dich freundlicherweise der Compiler 
aufmerksam gemacht hat, dürfte ein weiteres Problem stecken: Du benutzt 
die falsche Funktion für das, was du vorhast.
Und nein: "Bisher hat das aber funktioniert" ist keine gute Begründung. 
Was sagt die Doku von dieser Funktion, bzw. wie sieht die Funktion 
intern aus? Danach kann man sich leicht orientieren, was diese Funktion 
eigentlich wirklich macht. So wie sie jetzt ist, passt das nicht 
zusammen. So wie eine Baufirma, die mit einem Baukran anrückt, wenn es 
gilt das Erdreich für den Keller eines Hauses auszuheben. Das passt auch 
nicht. Für diese Arbeit braucht man einen Bagger und keinen Kran.

Die Datentypen von Funktionsparametern (und auch der Returnwert) 
erzählen einem etwas, wann man darauf achtet. Die sind nicht einfach nur 
dazu da, damit der Compiler etwas hat, woraus er Fehlermeldungen 
generieren kann.

von André W. (sefiroth)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
1
>   usb_write_character( (char*)&u8_USB_Keyboard_Ascii_Data);
2
>
>
>
> Wobei etwas einen Programmierer sofort stutzig machen sollte:
> Warum nimmt eine Funktion, die EINEN Character ausgeben soll, überhaupt
> einen Pointer auf diesen Character?
>
> Darauf gibt es keine vernünftige Erklärung und auch keinen vernünftigen
> Grund. Ganz im Gegenteil. Alles spricht dafür genau so etwas nicht zu
> tun und den Character einfach nur als Character zu übergeben. Man
> arbeitet nicht mittels Pointer, wenn man nicht muss. Und hier muss man
> nicht.

Da stimme ich Dir voll und ganz zu. Ich bin auch der Meinung, dass die 
Funktion falsch ausgelegt ist - aber sie ist nicht von mir und Teil 
eines großen Programmteils den ich gezwungermaßen übernehmen muss. 
Glaube mir, ich bin damit nicht glücklich und da stecken noch ein paar 
ganz andere Brummer drin :-( Wenn ich etwas Luft habe, werde ich mir das 
gesamte Programm von Grund auf vorknüpfen und es selber programmieren 
(wird schneller gehen als es zu reparieren).


> Die Chancen stehen gut, dass diese Funktion eben keinen einzelnen
> Character ausgibt, sondern einen String. Denn in diesem Fall würde man
> in der Funktionsschnittstelle dann tatsächlich einen char* erwarten.
> Entweder das, oder der Programmierer dieser Funktion war ein
> vollkommener und totaler Anfänger.

Letzteres ;-)

> In deinem "Problem", auf das dich freundlicherweise der Compiler
> aufmerksam gemacht hat, dürfte ein weiteres Problem stecken: Du benutzt
> die falsche Funktion für das, was du vorhast.
> Und nein: "Bisher hat das aber funktioniert" ist keine gute Begründung.
> Was sagt die Doku von dieser Funktion, bzw. wie sieht die Funktion
> intern aus? Danach kann man sich leicht orientieren, was diese Funktion
> eigentlich wirklich macht. So wie sie jetzt ist, passt das nicht
> zusammen. So wie eine Baufirma, die mit einem Baukran anrückt, wenn es
> gilt das Erdreich für den Keller eines Hauses auszuheben. Das passt auch
> nicht. Für diese Arbeit braucht man einen Bagger und keinen Kran.

Entschuldige, aber woher willst Du denn wissen, was die Funktion nicht 
die richtige ist? Ich weiß genau was die Funktion macht und ich bin mir 
darüber im Klaren, dass sie (wie einiges anderes) nicht sauber 
programmiert ist. Aber manchmal muss der Teufel halt Fliegen fressen und 
zusehen dass er fertig wird und sich nicht an einer Aufgabe mit 
untergeordneter Priorität festfrisst.

In dem Sinne: Danke für die Codezeile, aber bitte kreide mir nicht den 
Programmcode eines anderen an ;-)

von Karl H. (kbuchegg)


Lesenswert?

André Wippich schrieb:

>> Entweder das, oder der Programmierer dieser Funktion war ein
>> vollkommener und totaler Anfänger.
>
> Letzteres ;-)

In diesem Fall nehme ich alles zurück, was in meinem Beitrag danach noch 
gekommen ist.
Aber ehrlich gesagt habe ich damit nicht wirklich gerechnet. Jemand der 
in der Lage ist eine USB-Schnittstelle zu bedienen, sollte eigentlich 
grundlegende Dinge, wie Parameter-Passing, im kleinen Finger haben.

> aber sie ist nicht von mir
Das wollte ich auch nicht implizieren.
Das war mir schon klar, dass die nicht von dir sein wird. Sonst hättest 
du einfach den Argumenttyp gewechselt und es wäre gut gewesen.

von Karl H. (kbuchegg)


Lesenswert?

Aber damit das ganze noch zu was führt.
Ich würde mir überlegen, ob ich dem Compiler nicht noch eine
inline-Funktion anbieten würde
1
void usb_write_char( uint8_t c )
2
{
3
  usb_write_character( (char*)&c );
4
}
was ist der Sinn der Sache?
Zum einen verschwindet der cast damit in einer Funktion, was schon mal
gut ist. D.h an der Aufrufstelle brauchst du dich nicht mehr darum
kümmern.
Zum anderen kann der Compiler durch das inlinen den Code wieder
rausoptimieren - WENN ES MÖGLICH IST!

ein
1
   usb_write_char( data );
kostet dir durch inlinen nichts zusätzlich. Es kommt wieder der gleiche
Code raus.

Wohingegen dir der Compiler bei
1
  usb_write_char( 'A' );
die Arbeit des Definierens einer Hilfsvariablen abnimmt, die benötigt
wird, um eine Adresse weitergeben zu können.

Und last but not least, baust du damit für die Zukunft vor, wenn du dir
zugrundeliegende Funktion irgendwann mal korrigierst. Denn dann wirkt
sich die Korrektur nur mehr in dieser Zwischenfunktion aus und du musst
nicht quer durchs ganze Programm, um die Adressoperatoren zu entfernen. 
Auf die Art (mit kleinen inline Zwischenfunktionen) kannst du sukzessive 
den Code in kleinen Schritten auf 'vernünftig' umstellen, ohne dass du 
jetzt gleich alles machen musst.

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.