Hallo Leute, folgende Frage habe ich wie kann ich in einer Unterfunktion zwei Werte zurückgeben unswar als double. Ich habe überlegt das ganze mit pointern zu realisieren doch dann kann ich nur int werte zurückgeben kann mir einer helfen unten habe ich den code aufgeschrieben. int *mlMUlU32(unsigned int reg1,unsigned int reg2); main() { double *produkt; unsigned reg2= 5; unsigned reg1= 2 produkt =mlMulU32(reg1,reg2); printf("\n Die Ausgabe der Multiplikation ergibt Produkt= %u und %u",produkt1[0],produkt1[1]); } int *mlMlu32(unsigned int reg1,unsigned int reg2) { double *array[2]; unsignet int temparray[2]; double reg3; // Beide Werte werden zu double gecastet reg1 = (double)reg1; reg2 = (double)reg2; reg3 = reg1*reg2; temparray[0] = reg2; temparray[1] = reg3; array[0] = temparray[0]; array[1] = temparray[1]; return array; } So funktioniert das ganze, nur das ich als ausgabe zwei integer Werte kriege ich möchte aber double werte haben...die Ausgabe in printf("..") habe ich hier als %u unsigned variable wenn ich diese in %f ändere bekomme ich für beide werte Null. Kann mir einer weiter Helfen? Gruss Bjk
sorry die Ausgabe müsste so aussehen printf("\n Die Ausgabe der Multiplikation ergibt Produkt= %u und %u",produkt[0],produkt[1]);
Hallo bjk, probiers mal mit void blabla(int param1, int& param2) { param1 = param1 + 1; param2 = param2 + 2; } int main(void) { int p1 = 5, p2 = 5; cout << p1 << " " << p2 << endl; blabla(p1, p2); cout << p1 << " " << p2 << endl; return 0; } Jetzt wird ausgegeben: 2 5 2 6 Mit dem '&' im Funktionskopf von blabla(..) wird von dieser Variable keine lokale Kopie angelegt, sondern mit dem Original gearbeitet. Mit dem anderen Parameter läuft es wie gehabt. Modifikationen in der Funktion haben nur auf param2, bzw. p2 eine Wirkung im Hauptprogramm. p1 wird nicht verändert, obwohl param1 modifiziert wurde. MfG, Khani
Hallo khani, Danke für die Antwort,das sieht gut aus nur ist das nicht was ich wollte das jetzt bei meinem Code reg2 in der UNterfunktion benutzt wird ist nur zufall..folgendes: ich habe zwei eingangsparameter als integer, diese wandle ich in double um und berechne in der Funktion Zwei ganz neue Werte und will diese zwei Werte als double zurückgeben. Gruss Bjk
Also ich hab von C nicht so viel Ahnung, aber wenn ich mich richtig erinnere ging das so in der Art: void plus_eins(double* zahl1, double* zahl2) { *zahl1 += 1 *zahl2 += 1 } int main() { double zahl1 = 0, zahl2 = 0; plus_eins(&zahl1, &zahl2); return 0; } Nun müßte zahl1 und zahl2 meine ich gleich 1 sein. Du übergibst der Funktion zwei Doubles, welche du vorher erstellt hast. Die Funktion ändert diese Zahlen über Pointer auf sie nun direkt. Somit kann man soeit ich weiß mehr als "Funktionsergebnisse" bekommen. Bitte verbessert mich bei bedraf.
Hallo Benjamin, Danke hat so funktioniert das bedeutet wohl das in C kein rückgabetyp return definiert werden kann oder geht das auch anders? gruss Bjk
ach zu früh gefreut, dise Funktion geht nur wenn die Eingabeparameter double sind, ich wollte aber zwei integer Werte als Eingabeparameter haben, diese in double in der Funktion berechnen und als Double zwei verschiedene Werte ausgeben als die Eingabeparameter. Der Vorschlag von Benjamin aber verändert nur die Werte von zahl1 und zahl2..das sind aber die eingangswerte folgend sollte der Inhalt der Funktion sein void plus_eins(int* zahl1, int* zahl2) { // Beide Zahlen in double umwandeln zahl1 = (double) zahl1;// weiss nicht ob das so geht zahl2 = (double) zahl2; double zahl3; zahl3 = zahl1*zahl2; zahl2 = zahl1/zahl2; // Jetzt als return wert (Hier ist die Funktion void also kein returnwert möglich) return //beide werte (zahl3,zahl2) als double. } Ist das möglich oder nicht? gruss Bjk
Natürlich, auch wenn Du mir nicht geglaubt hast. Schreib : void blablubb(int zahl1, int zahl2, double& dzahl2, double& dzahl3) { double dzahl1 = double(zahl1); dzahl2 = double(zahl2); dzahl3 = dzahl1*dzahl2; dzahl2 = dzahl1/dzahl2; } int main(void) { ... blablubb(1, 2, x, y); ... return 0; } Das ergebnis steht in den double-Zahlen x und y. Ich empfehle Dir, mal ein gutes Buch zu C/C++ in die Hand zu nehmen, weil es so scheint, als wärst Du noch nicht sonderlich fit auf diesem Gebiet. Ist ein gut gemeinter Tip und kein Zusammenstauchen. Mit einem Buch und ein bißchen Übung hat mehr von den Antworten hier. Denn dann versteht man auch wirklich, was die Leutchen so meinen. MfG, Khani
Schau mal in einem C-Tutorial oder Buch nach dem Unterschied zwischen: call by value und call by reference Stefan
@ Lukas : Structs oder Klassen sind hier natürlich prinzipiell auch möglich, man sollte sie jedoch nur verwenden, wenn man a) sich keine Gedanken über die Verwaltung derselben im Speicher und den damit verbundenen Speicher-/Performanceverbrauch machen muss b) einen inhaltlichen Zusammenhang zwischen den Größen deutlich machen will. Auf einem Mikrocontroller ist die Methode mit dem "call by reference" oder die Arbeit mit der Originalspeicherstelle (wie von mir vorgeschlagen) besonders nett, da man nicht erst neue Speicherstellen verwalten muss, sondern einfach mit den alten arbeiten kann. Ganz nebenbei kann man sogar noch den Rückgabewert der Funktion für eine Statusrückgabe der Funktion (Fehlschlag/Überlauf...) benutzen. Auf dem PC (wo die Performance nach dem Moore'schen Gesetz eh völlig egal ist) kann man natürlich der Einfachheit halber auch Structs nehmen und hinterher eventuelle Probleme abfangen. MfG, Khani
Soweit ich weiß gibt es in C nicht den Referenzoperator &. Dieser gehört meines Wissens zu C++. Wenn du in C++ programmieren willst kannst auch den benutzen. Sonst hast du in C nur die Möglichkeit über die Pointer. Da bedeutet das "*" die Variable auf die der Pointer zeigt und beim Funktionsaufruf (void foo(&zahl)) bedeutet das "&" die Adresse der Variablen. Das du Integer haben willst zum berechen dürfte das durch einen Cast funktionieren. Beispiel: void foo(double* zahl) { int i = (int)*zahl); int z = i/3; *zahl = (double)z; } int void main() { double x = 6; foo(&x); x += 0.1 Ausgaben(*x); // Ausgabe() gibt z.B. denn Inhalt von *x // auf den Bildschirm aus return 0; } *x müßte nun als 2.1 ausgegeben werden.
"int i = (int)*zahl);" müßte natürlich "int i = (int)*zahl;" heißen. Also ohne die letzte Klammer. :)
Oh sorry. Haben deine Message nicht komplett gelesen. sorry. Dein Beispiel, bjk, kannst du so ändern: void plus_eins(double* zahl1, double* zahl2, double* zah3) { zahl3 = (double) zahl1*zahl2; zahl2 = (int) zahl1/zahl2; } und der Aufruf: plus_eins(&((double)eins), &((double) zwei), &((double)drei)); Hoffe das ist richtig und hilft dir.
@Khani: > Structs oder Klassen sind hier natürlich prinzipiell auch möglich, > man sollte sie jedoch nur verwenden, wenn man > a) sich keine Gedanken über die Verwaltung derselben im Speicher und > den damit verbundenen Speicher-/Performanceverbrauch machen muss Davon abgesehen, daß structs und Klassen zwei sehr verschiedene Dinge sind (da es Klassen nur in C++ gibt und sie dort einiges mehr veranstalten können als structs in C), mußt Du mir das mal erklären. Kann natürlich sein, daß ein bestimmter Compiler ineffizienten Code erzeugt für die Rückgabe einer struct, aber das ist dann ein Problem des Compilers, nicht der Methode. Zumindest ein AVR-GCC erzeugt für die Rückgaben einer struct fast identischen Code zu dem Fall, daß man stattdessen einen struct * übergeben würde. Außerdem habe ich im Ohr, daß Atmel selbst (natürlich aus deren Sicht für den IAR, müßte aber für GCC auch passen) die Benutzung von structs als effektive Programmierung angepriesen hat (hat mal jemand von einem Seminar berichtet, meiner Erinnerung nach in de.sci.electronics), da der Compiler dann Offset-Index-Adressierung benutzen kann, die effektiver ist als jedesmal die komplette Adresse laden zu müssen.
Hallo Jörg, ich möchte dazu nur so viel sagen : Der Unterschied zwischen Klassen und Structs ist lediglich die Kapselung. Sonst gibt es keinen. (Außer daß sie vielleicht in verschiedenen Programmiersprachen existieren.) Falls Du noch eingehender über das Thema mit mir diskutieren möchtest, kannst Du mir gerne eine Mail zum Thema schreiben, denn ich glaube nicht, dass eine solche Diskussion hier im Forum a) komplett verstanden wird und b) arg vielen Leuten was bringt. MfG, Khani
"Zumindest ein AVR-GCC erzeugt für die Rückgaben einer struct fast identischen Code zu dem Fall, daß man stattdessen einen struct * übergeben würde." Der war jetzt nicht ernst gemeint :-) Anbei mal ein Beispiel dafür. Die Funktion test1() mit struct als Returnwert belegt riesige 452% des Code im Vergleich zur Pointer Version test2(). Und auch deren Aufrufer muß noch stolze 162% an Code erzeugen. Das Problem ist nämlich, daß man in der Returnanweisung keine mehrfachen Zuweisungen machen kann. Man muß also erstmal eine lokale Instanz der Struktur anlegen und die Returnanweisung muß daß dann umständlich kopieren. Ebenso muß der Aufrufer erstmal umständlich einen Platz für eine 2. Kopie anlegen, damit dort die Returnanweisung etwas reinschreiben kann, was dann der Aufrufer wieder in das Original zurückkopiert. Daher auch noch mindestens 3-facher RAM-Bedarf (Original + 2 Kopien). Peter
Da muss ich Dir widersprechen, Khani: Gerade solche Diskussionen finde ich hier am interessantesten. Die heben sich wohltuend ab von den endlosen Entprell-Diskussionen ;-) Also wenn Ihr das per Mail ausmacht, dann bitte auch cc an mich. Ich persönlich denke, dass die Parameterübergabe mittels eines Struct-Pointer eine der effektivsten Methoden ist. Was gcc macht, wenn man eine struct call-by-value übergibt, habe ich noch nicht ausprobiert. Stefan
Hier nochmal das Ganze mit Pointer auf die Struktur. Spart dann nochmal ein kleines bischen Code (4 Worte). "Ich persönlich denke, dass die Parameterübergabe mittels eines Struct-Pointer eine der effektivsten Methoden ist." Was hiermit bewiesen ist. Wenn man die -> Schreibweise verstanden hat ist das auch kein Problem mehr. Peter
Hallo, mittles Parameterübergabe durch Strukturen hat man auch den Vorteil das man die Anazhl der Parameter relativ leicht Ändern kann. Man braucht dann nur in der Stuktur den Parameter zu ändern und an der Stelle an dem man mit dem Parameter arbeitet. Die Übergabeschnittstelle bleibt dann immer gleich und man braucht nicht immer den Funktionsprototyp und den Funktionskopf anzupassen. Gruß MarkusS
Hi, Man sollte sich bei der Auswahl der Methoden auch immer mit an der Lesbarkeit der Quellen orientieren. Das heist, das man eine Structur nur dann verwenden sollte wenn die einzelnen Werte auch logisch zusammengehören. Ansonsten ist call by reference mit einem Errorcode als Ergebnis die günstigere Variante. Übrigens theoretisch giebt es klassen nur bei C++, aber einige C-Compilier verstehen das Schlüsselwort class trotzdem. In C++ ist der Unterschied das Elemente von Klassen standardmäßig private sind und bei Strukturen public. Will man das jeweils andere erreichen oder die Element preotected deklarieren muss man das explizit angeben. Da in der OOP ein Grundprinzip die Datenkapselung ist verwendet man meist Klassen. Andreas Andreas
@Peter: Tja, Peter, wenn Du schon degenerierte Testfälle benutzt, dann wirf bitte nicht mit Prozentzahlen herum, wenn der Unterschied am Ende ein paar Bytes beträgt. Man kann mit beliebig sinnlos konstruierten Testbeispielen natürlich am Ende alles beweisen. ;-) Einen double anzulegen, um ihn dann im Aufrufer in int wandeln zu lassen (dem Gerufenen jedoch damit das aufwendige Registerreten für double anzulasten), halte ich schon für etwas schräg. Dein Testbeispiel 2 vergleicht Äpfel mit Birnen (struct gegen call by reference), das lasse ich daher gleich erstmal außen vor -- der Fragesteller hatte explizit nach structs gefragt. Ob dies nun für die Datendarstellung sinnvoll ist oder nicht, mag er selbst entscheiden. Wie andere schon schrieben, haben beide Ansätze ihr Für und Wider. Meine Bemerkung, daß der AVR-GCC ein struct return wie eine Referenz auf eine struct behandelt, bezog sich ausdrücklich nicht darauf, daß man es auch ohne struct machen könnte. Deine Testerei sieht dann für Dein double-Beispiel so aus (-mmcu=atmega128, -Os): /* function test1 size 72 (37) */ /* function caller1 size 76 (41) */ /* function test3 size 18 (17) */ /* function caller3 size 45 (26) */ also 148 Worte für die struct-Rückgabe gegen 53 Worte für die übergabe des struct *. Nun dreh' mal das double auf unsigned char (schließlich willst Du es ja am Ende nur auf einen Port ausgeben), dann hast Du: /* function test1 size 3 (2) */ /* function caller1 size 5 (4) */ /* function test3 size 6 (5) */ /* function caller3 size 27 (8) */ 8 Worte für Lösung 1 gegen 33 Worte für Lösung 3, oder einen Overhead von 400 % (:-) Deiner bevorzugten Variante. So viel zur Aussage eines degenerierten Testbeispiels. ;-) Fazit: es muß sich schon jeder für seine ganz konkrete Applikation eine Rübe machen, welche der Methoden am effektivsten ist. Btw: #include <avr/io.h>, nicht #include <io.h>. <io.h> ist nicht von irgendeinem Standard abgedeckt, daher steht er im Unterverzeichnis avr. @Khani: > Der Unterschied zwischen Klassen und Structs ist lediglich die > Kapselung. Sonst gibt es keinen. In C++, weil dort auch eine struct letztlich eine Klasse ist, ggf. mit allem Overhead, der daraus resultieren kann. In C ist eine struct als solches nicht schwergewichtig. Sie kann keine Methoden haben, landet niemals in einer virtuellen Methodentabelle, ruft keine Konstruktoren beim Anlegen oder Destrukturen am Ende des Scopes etc. pp. Insofern kann ich der generellen Aussage ,,Wer structs im Mikrocontroller benutzt, bläht seinen Code ja automatisch künstlich auf.'', die da von Dir rüberkam, nicht folgen. Man kann sicher auch in C++ mit structs oder Klassen vernünftig und speichersparsam umgehen (schließlich gibt es auch Bemühungen um eine Standardisierung eines Subsets von C++ für embedded applications), aber es gehört schon ein wenig Kenntnis des Verhaltens verschiedener Sprachelemente dazu -- sonst kein ein vergessenes &-Zeichen großen Schaden anrichten.
Mensch Jörg, weniger aufregen - länger leben. Ich kenne 1. den Unterschied zwischen C und C++ und 2. auch die beiden Sprachen recht genau (auch bezgl. dem was hinten rauskommt). Also : Du hast Deine Meinung, ich habe meine und ich akzeptiere Deine Einstellung, auch wenn ich nicht so verfahre. MfG, Khani P.S.: Immer diese Glaubenskriege ;-)
@Jörg, ich hatte deshalb "double" genommen, weil das ja oben so gefordert wurde. Und die Zuweisung zu den Ports habe ich nur zur Sicherheit gemacht, damit mir nicht der ganze Code wegoptimiert wird. Das es bei "char" nun ganz anders aussieht ist wirklich verblüffend. Peter
Ich hatte mich mit ,,degenerierter Testfall'' auch nur darauf bezogen, daß Deine Prozentzahlen letztlich nur daraus resultierten, daß die eine Lösung im Vergleich zur anderen in dieser zusammengestrichenen Version vor allem ihren Aufwand im umständlichen Retten von sackweise Registern verplempert hat, gar nicht so sehr im eigentlichen Code. Wenn man nun statt des konstruierten Testfalles ein real world example nimmt, ist das Retten der Register sehr wahrscheinlich ohnehin schon nötig, damit dürften die Unterschiede zwischen beiden Verfahren in der Praxis minimal sein. Ich würde übrigens selbst auch nicht auf die Idee kommen, eine struct zurückzugeben (dazu kenne ich halt auch noch die Zeiten von K&R C zu gut ;-), ich war auf die meiner Meinung nach doch recht elegante Variante der struct-Rückgabe (die ja letztlich ein call by reference ist) nur gestoßen, als ich mir letztens mal angesehen habe, wie der AVR-GCC das denn überhaupt abhandelt. Hatte mich interessiert, da Atmel ursprünglich ein ELF-ABI veröffentlichen wollte und mich um eine Zuarbeit dazu gebeten hat. (Allerdings sind die Unterschiede zwischen den verschiedenen Compilern bezüglich ihrer Strategie zu groß, so daß ein ABI keinen Sinn hat. Naja, ist zumindest auch ein Ergebnis.)
Ich bevorzuge in der Regel die Variante 2 wegen Schreibfaulheit. Die Variante 1 hatte ich hier das erste mal ausprobiert. Es gibt allerdings noch eine 4. Variante, nämlich globale Variablen. Das wird auch öfter gemacht, z.B. gibt es oft eine globale Variable "Error", in die dann verschiedene Funktionen ihr Mißlingen reinodern. Es bleibt dann dem Programmierer überlassen, wie spät oder früh er das Mißlingen einer oder mehrerer Funktionen prüfen will. Durch das Odern bleiben die Fehler ja bis zum Test der Variable erhalten. Peter
In C kannst du nur immer ein Wert aus einer Funktion zurückgeben, egal welcher Dateityp. Das einfachste ist, das du die Variablen die du zurückgegen willst global, sprich vor deiner main funktion deklarierst. Dann kannst du dir das ganze Spielchen mit Pointer und Structuren sparen.
Och nee, nicht wieder alles von vorn... Es sind alle Möglichkeiten doch schon diskutiert worden. Globale Variablen sind eine davon, aber bei weitem nicht die einzige und auch nicht immer ,,die einfachste''.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.