Hallo,
auf
https://www.einplatinencomputer.com/raspberry-pi-uart-senden-und-empfangen-in-c/
habe ich folgenden Code gefunden, um den uart bei einem RaspberryPi zu
benutzen.
zum senden wird ein pointer auf einen buffer gelegt.
Was hat das für einen hintergrund? warum verwendet man den buffer nicht
direkt?
Der kann ja auch eine länge von 100 oder so haben. Bei der funktion
write wird dann ja die länge mitgegeben.
Alex schrieb:> zum senden wird ein pointer auf einen buffer gelegt.
Wenn du den ganzen Buffer an die Funktion übergeben würdest, müsste er
auf den Stack der aufgerufenen Funktion kopiert werden, denn
Funktions-Argumente sind in C immer "by value" (eine Kopie).
> Wenn du den ganzen Buffer an die Funktion übergeben würdest, müsste er> auf den Stack der aufgerufenen Funktion kopiert werden, denn> Funktions-Argumente sind in C immer "by value" (eine Kopie).
Die übergebene "value" ist der Pointer auf den Buffer. Bei z.B.
1
write(fd,"Hello World\n",12);
2
oder
3
write(fd,buffer,strlen(buffer));
wird nichts kopiert. Komplette Arrays kannst du nur über Umwege "by
value" übergeben und wird aus den von dir genannten Gründen als
schlechter Stil angesehen.
Der Kode ist von einem Programmieranfänger geschrieben und sollte nicht
als Beispiel für saubere oder sinnvolle Programmierung angesehen werden.
Stefanus F. schrieb:> Wenn du den ganzen Buffer an die Funktion übergeben würdest, müsste er> auf den Stack der aufgerufenen Funktion kopiert werden, denn> Funktions-Argumente sind in C immer "by value" (eine Kopie).
Das heisst TX ist nur so groß, wie es elemente hat?
foobar schrieb:> Der Kode ist von einem Programmieranfänger geschrieben und sollte nicht> als Beispiel für saubere oder sinnvolle Programmierung angesehen werden.
ob jetzt jedes Element einzeln geschrieben, oder ob man TX mit strncpy
beschreiben würde.
Ist das mit dem Pointer auf dem BUF_TX denn so gängig? Bzw. eine 'gute'
Methode?
Oder wie sollte es man besser machen?
> ob jetzt jedes Element einzeln geschrieben, oder ob man TX mit strncpy> beschreiben würde.> Ist das mit dem Pointer auf dem BUF_TX denn so gängig? Bzw. eine 'gute'> Methode?> Oder wie sollte es man besser machen?
Das (leicht gekürzte) Original:
Such dir selbst aus, welche Variante "besser" ist. Programmierer sind
flexibel - man nutzt das, was gerade am besten passt. Die erste
Variante aber wohl eher selten ...
PS: Variablen nur aus Großbuchstaben sind ein "no go" - die Namen sind
für den Präprozessor ("defines") reserviert.
Stefanus F. schrieb:> Wenn du den ganzen Buffer an die Funktion übergeben würdest, müsste er> auf den Stack der aufgerufenen Funktion kopiert werden, denn> Funktions-Argumente sind in C immer "by value" (eine Kopie).foobar schrieb:> oder, wenn man, z.B. wegen dynamischer Daten, einen Buffer nutzen> möchte: char buffer[64];>> sprintf(buffer, "Raspberry pi, 3*4=%d\n", 3*4);> out = write(uart0_filestream, buffer, strlen(buffer));
Dazu habe ich nochmal eine Nachfrage. Den weg von foobar habe ich sonst
auch immer gemacht, wenn ich arrays an einer Funktion übergeben habe.
Stefanus F. aussage habe ich jetzt so verstanden, dass auch wenn ich
eine länge kleiner der länge des Arrays angegeben wird, der komplette
Array (also 64 Elemente) in die Funktion kopiert.
Wenn ich einen Pointer auf den buffer mache und diesen dann mit der
entsprechenden länge übergebe, ist der pointer auch nur so lang wie
beschrieben (im obigen Beispiel also 12).
Habe ich das so richtig verstanden?
Alex schrieb:> Das heisst TX ist nur so groß, wie es elemente hat?
TX ist ein Zeicher auf ein Array von Zeichen. Also 32bit oder 4 Bytes,
unter der Annahme, dass bei diesem System all Zeiger 32bit groß sind.
> Ist das mit dem Pointer auf dem BUF_TX denn so gängig? Bzw. eine 'gute'
Methode?
Ja und Ja, sonst wäre das in der Standard-C Bibliothek nicht so
festgelegt. Die Bibliothek ist zwar alt, aber ihr Erfinder war kein
Dummkopf und hatte bereits viele Jahre Erfahrung mit anderen
Programmiersprachen.
Johannes schrieb:> Stefanus F. aussage habe ich jetzt so verstanden, dass auch wenn ich> eine länge kleiner der länge des Arrays angegeben wird, der komplette> Array (also 64 Elemente) in die Funktion kopiert
Ist falsch, wird nicht kopiert. Arrays degenerieren zu Zeigern.
Sebastian schrieb:> Arrays degenerieren zu Zeigern.
Ja, das hatte mich anfangs auch irritiert. Schau Dir das an:
1
char*du="Johannes";
Hier wird irgendwo ein char[] angelegt, mit dem Wort "Johannes" befüllt
und mit einem \0 abgeschlossen. Das Array ist also 9 Bytes groß. "du"
ist ein Zeiger auf dieses Array.
1
charich[]="Stefan";
Das hier ist technisch fast das Gleiche. Ehrlich gesagt weiß ich ich
nicht, wo genau der Unterschied ist, denn man kann char[] und char*
gleicher benutzen und mixen:
1
char*du="Johannes";
2
charich[]="Stefan";
3
4
charersterBuchstabe=du[0];
5
charersterBuchstabe=ich[0];
6
7
charersterBuchstabe=*du;
8
charersterBuchstabe=*ich;
9
10
printf("Der Name ist: %s",du);
11
printf("Der Name ist: %s",ich);
12
13
voidsende_string(char*name){
14
while(*name!='\0'){
15
sende_zeichen(*name)
16
}
17
}
18
19
voidsende_string(charname[]){
20
while(*name!='\0'){
21
sende_zeichen(*name)
22
}
23
}
24
25
voidsende_string(char*name){
26
for(inti=0;name[i]!='\0';i++){
27
sende_zeichen(name[i])
28
}
29
}
30
31
voidsende_string(charname[]){
32
for(inti=0;name[i]!='\0';i++){
33
sende_zeichen(name[i])
34
}
35
}
Alle vier Funktionen kannst du wahlweise mit "ich" oder "du" aufrufen. C
übergibt Arrays an Funktionen immer als Zeiger.
Stefanus F. schrieb:> Funktions-Argumente sind in C immer "by value" (eine Kopie).
Trifft bei Pascal zu, aber nicht bei C!
Funktions-Argumente von Arrays, Strukturen und Strings sind in C immer
"called by reference" .
> Stefanus F. schrieb:>> Funktions-Argumente sind in C immer "by value" (eine Kopie).GEKU schrieb:> Trifft bei Pascal zu, aber nicht bei C!> Funktions-Argumente von Arrays, Strukturen und Strings sind in C immer> "called by reference" .
Ja, ich habe das missverständlich ausgedrückt. Die Übergabewerte werden
immer auf den Stack der aufgerufenen Funktion kopiert, oder in CPU
Registern übergeben.
Arrays und Strukturen zerfallen dabei zu Zeigern, weil es in der Regel
keinen Sinn macht, größere Datenmengen zu kopieren. Es werden Zeiger auf
die Daten übergeben.
Gibt es den Begriff "Referenz" überhaupt in C? Ich kenne nur Zeiger.
Stefanus F. schrieb:> Gibt es den Begriff "Referenz" überhaupt in C? Ich kenne nur Zeiger
Ich denke schon.
http://www.lerneprogrammieren.com/blog/praxis/call-value-und-call-reference-bei-der-parameteruebergabe
Der Vorteil in Pascal von "called by value" ist, dass die ursprüngliche
Zeichenkette erhalten bleibt auch wenn in die in die Funktion übergebene
Zeichenkette (Kopie) verändert wird.
In C kann das nur mit dem Attribut const zur Compilerzeit verhindert
werden.
(es wird eine Kopie im Unterprogramm erzwungen)
Allerdings kostet "called by value" viel Platz am Stack bzw. viel
Rechnerleistung, die im embedded Bereich sowieso zu kostbar sind.
> Das hier ist technisch fast das Gleiche. Ehrlich gesagt weiß ich ich> nicht, wo genau der Unterschied ist>
1
>char*du="Johannes";
2
>charich[]="Stefan";
3
>
Du merkst den Unterschied, wenn du den Variablen Werte zuweisen willst
oder per sizeof die Größe abfragst ;-)
"du" ist der Name eines Pointers, der auf einen (anonymen,
initialisierten) Datenblock zeigt. "ich" ist der Name eines
(initialisierten) Datenblocks.
In Pseudoassembler ungefähr so:
> Funktions-Argumente von Arrays, Strukturen und Strings sind in C immer> "called by reference"
Nicht ganz. Arrays, Strings (Arrays von Zeichen) und Funktionen
degenerieren zu Pointer und werden als Pointer übergeben. Strukturen
werden aber neuerdings (ab C89 oder so ;-) ) kopiert! Wird
glücklicherweise selten benutzt - meist unbewusst von Anfängern.
foobar schrieb:> Du merkst den Unterschied, wenn du den Variablen Werte zuweisen willst> oder per sizeof die Größe abfragst ;-)
Ach ja, logisch. Also kenne ich den Unterschied ja doch, war mir nur
nicht bewusst.
foobar schrieb:> Strukturen werden aber neuerdings (ab C89 oder so ;-) ) kopiert!
Oh, das ist gemein. Bei STM32 habe ich mal gemerkt, dass bis zu 5
Parameter in Registern übergeben werden. Bei mehr wird Stack verwendet.
Bei Strukturen muss man dazu wohl die einzelnen Elemente zählen, oder?
> Bei Strukturen muss man dazu wohl die einzelnen Elemente zählen, oder?
Keine Ahnung, wie das bei ARM/STM32 ist - wird in der ABI (Application
Binary Interface) festgelegt und kann teilweise noch per Compilerswitch
modifiziert werden (bei ARM z.B. gibt es mehrere verschiedene ABIs).