paulchen schrieb:> int8_t addiere5_Copy(int8_t variable)> {> int8_t return_value=0;> return return_value = variable +5;> }
Das ist doch total sinnlos, warum nicht
1
int8_taddiere5_copy(int8_tvariable){
2
returnvariable+5;
3
}
Ansonsten sind beide Varianten zwar funktional identisch, aber der
generierte Maschinencode sieht etwas anders aus. Generell ist die 1.
Version zu bevorzugen, weil bei dieser ganz genau klar ist, was Eingabe
& Ausgabe ist ("variable" ist Eingabe, Rückgabewert ist Ausgabe) und bei
der zweiten der Parameter doppeltgenutzt wo nicht immer so
offensichtlich ist was passiert.
Parameter sind für Eingaben, Rückgabewerte für Ausgaben.
Die 1. Version ist in diesem Fall vermutlich auch minimal effizienter...
Hallo,
Danke für die Erklärung.
>Das ist doch total sinnlos, warum nicht>int8_t addiere5_copy (int8_t variable) {> return variable + 5;>}
Ja das ist klar sollte nur ein Beispiel sein.
Gruß paulchen
Wie Du schon richtig geschreiben hast, wird in der ersten Variante eine
Kopie der Variable für die Funktion erstellt. Bei einem Byte geht das
ratz fatz und braucht bestimmt weniger Platz als ein Zeiger. Ausserdem
pflichte ich meinem Vorredner bei, dass klarer ist was in die Funktion
nur rein gehen kann und sich dadurch nicht ändert und wo etwas aus der
Funktion raus kommt.
Variante 2 kommt erst wieder zum Zug, wenn nicht ein Byte, sondern
Hunderte bis Tausende übergeben werden sollen und Ausführungszeit oder
Datenspeicherplatz ein kanppes Gut sind. Dann werden nämlich auf einmal
Hunderte bis Tausende von Bytes kopiert. Das Kopieren braucht Zeit und
die Werte stehen doppelt im Speicher. Dagegen ist ein Zeiger, der
übergeben wird eher klein.
Problematisch ist dabei, dass die Funktion Zugriff auf das Original der
Eingangsdaten hat und daran herumfummeln könnte. C bietet zwar die
Möglichkeit einen Zeiger auf eine Konstante zu definieren, aber wenn man
Mikrocontroller programmiert hat man u.U. einen Compiler der über die
Frage konstant oder nicht nicht versucht den Adressraum (Programm für
Konstante; Daten für Variablen) zu bestimmen. Da bleibt also nur
entweder im Büro eine Guillotine zu errichten und anzudrohen, dass jeder
drauf landet, der in so einer Funktion schreibend auf die Eingabedaten
zugreift oder einen leistungsfähigeren Mikrokontroller einzusetzen, bei
dem das Kopieren nicht auffällt.
fop schrieb:> C bietet zwar die> Möglichkeit einen Zeiger auf eine Konstante zu definieren, aber wenn man> Mikrocontroller programmiert hat man u.U. einen Compiler der über die> Frage konstant oder nicht nicht versucht den Adressraum (Programm für> Konstante; Daten für Variablen) zu bestimmen.
Das bedeutet also bei einem solchen Compiler kann man einen non-const
Pointer nicht in einen const-Pointer konvertieren, weil der Zugriff auf
const-Pointer anders geregelt wird? Das wäre dann aber weit weg von C
und geradezu gefährlich. Funktionen wie memcpy, strlen etc. kann man
dort dann also auch nicht verwenden. Gibt es tatsächlich Compiler, die
so etwas machen?!
Der umgekehrte Fall sieht natürlich ganz anders aus, wenn der Compiler
eine Konstante in Read-Only-Memory legt und man bei einem Pointer darauf
das "const" wegcastet und dann darauf schreibt - da ist es ok wenn es
nicht funktioniert.
Dr. Sommer schrieb:> Das bedeutet also bei einem solchen Compiler kann man einen non-const> Pointer nicht in einen const-Pointer konvertieren, weil der Zugriff auf> const-Pointer anders geregelt wird? Das wäre dann aber weit weg von C> und geradezu gefährlich. Funktionen wie memcpy, strlen etc. kann man> dort dann also auch nicht verwenden. Gibt es tatsächlich Compiler, die> so etwas machen?!
non-const in const casten geht natürlich.
Nur andersrum geht es nur in Einzelfällen und nicht unbedingt portabel.
Z.B. void *memcpy(void *dest, const void *src, size_t n):
Da darf als dest kein const-Pointer angegeben werden, auch wenn es bei
manchen Systemen durch den Compiler geht und vielleicht sogar
funktioniert - es geht aber dann nur auf eigene Gefahr.
Richtig wäre es nur, Daten, die ursprünglich nicht-const sind, dort zu
übergeben (bzw. einen Zeiger auf solche).
Für src dagegen garantiert das obige const nur, daß die Funktion memcpy
über den Zeiger nichts verändert.
Der Aufrufer darf aber auch nicht-const-Zeiger übergeben, die Quelle muß
also nicht const sein.
Hier ist also das nicht-const von dest einschränkender als das const von
src.
Was fop wohl meint mit der unterschiedlichen Behandlung von Const und
nicht-const je nach Compiler, ist nicht das Herumreichen von Zeigern,
sondern die ursprüngliche Anlage von Daten in einem schreibgeschützten
oder beschreibbaren Bereich.
Das wird im Nachhinein durch das Herumreichen von Zeigern natürlich
nicht mehr geändert, auch wenn man mehr oder weniger frei const dazu
oder wegcasten kann.
Beispiel:
1
constchar*p="Hallo";
2
*p='X';// Compiler sagt: geht nicht, weil p ist const char*
3
*(char*)p='X';// mag für den Compiler ok sein, scheitert evtl. zur Laufzeit
4
...
5
char*q="Hallo";
6
*q='Y';// mag für den Compiler ok sein, scheitert evtl. zur Laufzeit
Ob das Überschreiben des 'H', auf das p zeigt, zur Laufzeit klappt,
hängt vom System ab: wenn die Konstante in schreibbarem RAM liegt, fällt
der Fehler gar nicht auf. Auf anderen Systemen kann es einen
Programmabbruch geben.
Interessant ist, daß die letzte Zeile mit *q auf manchen Systemen sogar
den String verändert, auf den p zeigt, nämlich dann, wenn der Compiler
nicht mit der Blödheit vieler Programmierer rechnet. Da "Hallo" eine
Konstante ist, darf man sie nicht über Zeiger ändern (auch wenn es
gelegentlich klappt), und ein halbwegs intelligenter Compiler legt
gleiche Stringkonstanten aus Geiz nur einmal an.
Das Casten zwischen const und nicht-const wird häufig falsch gemacht und
zeigt schnell, wer Herumpfuschen als Programmieren verkauft.
Dr. Sommer schrieb:> fop schrieb:>> C bietet zwar die>> Möglichkeit einen Zeiger auf eine Konstante zu definieren, aber wenn man>> Mikrocontroller programmiert hat man u.U. einen Compiler der über die>> Frage konstant oder nicht nicht versucht den Adressraum (Programm für>> Konstante; Daten für Variablen) zu bestimmen.> Das bedeutet also bei einem solchen Compiler kann man einen non-const> Pointer nicht in einen const-Pointer konvertieren, weil der Zugriff auf> const-Pointer anders geregelt wird? Das wäre dann aber weit weg von C> und geradezu gefährlich. Funktionen wie memcpy, strlen etc. kann man> dort dann also auch nicht verwenden. Gibt es tatsächlich Compiler, die> so etwas machen?!
Das ist übliche Praxis: (nicht-volatile) readonly-Objekte werden nach
.rodata gelegt, andere nach .data oder .bss. Bei relocatiblem Code
heißen die Sections anders, aber im Endeffekt läuft es aufs gleiche
hinaus.
Für die Anwendung muß das aber 100% transparent sein, d.h. ein Zugriff
auf .rotata sieht genauso aus wie einer auf .data. Evtl. unterscheiden
sich die Zugriffe im Timing, aber darüber macht der Sprachstandard eh
keine Aussage.
Übrigens legt auch avr-gcc const Objekte nach .rodata, allerdings legt
das Standard-Linkerscript .rodata in den RAM — eben weil nur so
sichergestellt ist, daß es 100% transparent ist. Es gibt auch Devices,
die den Flash in den RAM-Adressbereich mappen. Hier könnte man .rodata
ins Flash legen und Linkerscript und Startup-Code darauf anpassen. Aber
selbst dann bleibt es für die Applikation transparent, da all zugriffe
gleich aussehen denn für den Flash-Zugriff wird eben kein LPM mehr
gebraucht.
> Der umgekehrte Fall sieht natürlich ganz anders aus, wenn der Compiler> eine Konstante in Read-Only-Memory legt und man bei einem Pointer darauf> das "const" wegcastet und dann darauf schreibt - da ist es ok wenn es> nicht funktioniert.
Jo, steht auch im C-Standard drinne das dies undefiniertes Verhalten
bedeutet.
Klaus Wachtler schrieb:> non-const in const casten geht natürlich.> Nur andersrum geht es nur in Einzelfällen und nicht unbedingt portabel.
Ja, genau das meinte ich ja...
Johann L. schrieb:> Für die Anwendung muß das aber 100% transparent sein, d.h. ein Zugriff> auf .rotata sieht genauso aus wie einer auf .data.
Ja.
Johann L. schrieb:> Hier könnte man .rodata> ins Flash legen und Linkerscript und Startup-Code darauf anpassen. Aber> selbst dann bleibt es für die Applikation transparent, da all zugriffe> gleich aussehen denn für den Flash-Zugriff wird eben kein LPM mehr> gebraucht.
Ja, zB alle ARM-Controller. Das ist der große Vorteil von vermutlich
allen(?) 32bit-Controllern, weil deren Adressraum groß (4GB) genug ist
für Flash, RAM, I/O, s.d. man alles mit den selben Instruktionen
abhandeln kann. An eine Funktion die ein "const char*" nimmt kann man so
flash-strings und RAM-Strings übergeben...