![]() |
Speicher und Funktionen in C
Hi.
Ein Funktionsaufruf: funktion(argument1); Wird argument1 im Speicher neu angelegt? Und falls ja, ist nicht dann ein Pointer auf argument1 weniger speicherverbrauchend (falls argument1 zum Beispiel eine Struktur wäre)? Mir ist klar, dass funktion(&argument1) die Möglichkeit hat argument1 zu ändern, funktion(argument1) kann das hingegen nicht. Oder seh ich das falsch? Danke für eure Mühe. -- lg fabsi |
Ja. du hast das absolut richtig verstanden.
mfg c. |
Danke. :)
Und was ist zu bevorzugen? Die Übergabe eines Pointers auf den Inhalt, oder des Inhalt selbst (bzw. eine Kopie des Inhalts)? Oder von welchem Standpunkt aus ist was zu bevorzugen eurer Meinung nach? (Das ichs mir selbst aussuchen kann wie ichs mach ist mir klar, aber es hat sicher wer Erfahrungen mit der einen oder anderen Methode, und die interessieren mich.) mit Dank im Voraus. -- lg fabsi |
...das kommt draufan...
wenn du sichergehen willst/musst, dass eine funktion einen übergabewert nicht verändern darf (aus welchen gründen auch immer, hab täglich damit zu tun :D), würd ich immer den "call-by-value" bevorzugen. wenn das allerdings keine rolle spielt, sondern eher speichereffizienz, ist es besser, die referenz (&value) zu übergeben |
Zitat:
Code:
void foo (const void* value) Zitat:
bsp: sizeof (short*) ist bei mir zb 4 sizeof (short) ist bei mir 2 sprich würd ich die referenz übergeben hätt ich dann meine originalvariable mit 2 + einen pointer mit 4 bytes -> 6 bytes. call by value hätt ich 2 shorts -> 4 bytes |
1) Call by Address setzt das Präparieren der Struktur (=Versorgen der Datenfelder mit Werten) voraus. D.h. ein Call bei Address ist im Fall einer Struktur generell zu bevorzugen, da ich vorher eine definierte Versorgung der Datenfelder sicherstellen muss. Dies zwingt zu sorgfältiger Programmierung.
2) Ein weiterer Grund ist die Verwaltung der Informationen (Struktur) im Computerspeicher. Ein Array aus Strukturen oder eine verkettete Liste bzw. ein Baum aus Strukturen kann besser verwaltet werden als das Anlegen von einzelnen Strukturen. Die Übergabe erfolgt aus dem Array/der Liste/dem Baum oder aus einer Kopie UNTER VORHERIGER Versorgung der Strukturkopie und Übergabe eines Zeigers darauf. Punkt 1 bezieht sich auf die Disziplin beim Programmieren Punkt 2 auf die Praxis, Geschwindigkeit und Effizienz bei der Speicherorganisation Es ist ein Muss eine Struktur vor der Übergabe mit korrekten Werten zu versorgen, insofern ist die zusätzliche Übergabe der Daten der Struktur über den Stack (Call by Value) ein Unsinn erster Ordnung. mfg Kikakater |
ich habs nicht mit char oder int datentypen zu tun sondern mit Strukturen, die ihrerseits wieder strukturen, int arrays, einfachen int Datentypen enthalten. Wenn der Pointer auf meine Struktur seine 4 Byte hat kann ich damit leben, die Struktur hat sicher ein Vielfaches davon wenn ich sie selbst übergebe.
Die Methode den Übergabewert als Konstante zu übergeben gefällt mir. Danke für den Tip. :) Warum interessiert mich das? Ich überleg mir bei einem Softwareprojekt den Funktionsaufrufen ein einheitliches Aussehen zu verpassen, und zerbreche mir den Kopf, was das Beste sein könnte. Danke für eure Antworten @Stona & @Who-T. Will noch wer seine Erfahrungen mitteilen? |
noch ne infos zur übergabe von Arrays an andere Funktionen (wenn du's nicht weisst oder dich interessiert):
wenn du ein array als parameter übergibst wird - egal ob du schreibst funktion (&array[0]); oder funktion (array); immer ein pointer auf das erste element des arrays übergeben (auch im fall zwei), d.h. du kannst ein array nicht als kopie übergeben. Pointer und Arrays in C sind ja sehr eng miteinader verwandt. @Who-t hast natürlich recht ;) aber siehst, seine daten sind viel großer ale ne adresse (ich wusste das natürlich) :p |
Zitat:
Die Referenz ( function_name (data_type &reference) ) bedeutet eine Übergabe einer Adresse unter syntaktischer Verwendung einer Datenvariablenschreibweise innerhalb der Funktion ! Das ist der Unterschied zu Call by Address. Call by Reference existiert nur in C++, nicht jedoch in C. Der Aufruf mit einem Ampersand '&' unter C ist die Übergabe einer Adresse und nicht einer Referenz. |
@kikakater
Wieso ist das ein Muß die Strukturen mit korrekten Werten zu Versorgen? Reicht das Anlegen eines Pointers auf eine Struktur (in main() ) und das anschliessende "anlegen" von Speicher und zuweisen von Werten in initStruktur(pStruktur) (als funktionsaufruf in main()) nicht aus? @Stona Ja, das wußte ich schon. :) Ahja, es geht um reinen C Code, es kommt (ausser C++ Kommentaren :-) ) nix C++ mässiges vor. Meine Dankbarkeit weitet sich auch auf kikakater aus. |
@fabsi: Bitteschön ;)
Das reicht aus ! Der initStruktur(pStruktur) Aufruf ist ja ein Versorgen der Datenfelder dieser Struktur. Insofern genau das was ich angesprochen habe mit dem Versorgen vor dem Aufruf von Arbeitsfunktionen, die diese Struktur benützen. Mir geht es aber um Arbeitsfunktionen, die die Struktur in erster Linie nicht mit Werten beschicken, sondern die Werte diverser Datenfelder der Struktur nach der Übergabe zur Steuerung und als Parameter verwenden. Zu diesem Zeitpunkt ist eine Initialisierung der Struktur per definitionem - zumindest teilweise und im Wesentlichen - erfolgt - Ergänzungen, Übersteuerungen und Standardwertversorgungen einmal ausgenommen. |
@kikakater
aso, ok. Im allgemeinen denkt man auch an Arbeitsfunktionen und für die muß das natürlich zutreffen. |
Zitat:
Gibts eine Möglichkeit nur Pointer zu übergeben und trotzdem sicherzustellen, dass die Funktion die Daten auf die der Pointer zeigt nicht verändert? |
Die Möglichkeit gibt es: Einfach in der Funktion nicht auf die Datenfelder schreibend zugreifen.
Eine andere Variante gibt es nicht, sollte eigentlich logisch sein ... Nur in C++ gibt es einen protected Zusatz, der bezieht sich aber wiederum nur auf Funktionen, die nicht auf protected Variablen zugreifen dürfen. Mit anderen Worten schaut die Sache letztgültig so aus (:rolleyes: *seufz* es ist so, nicht eine Bemerkung in Deine Richtung): 1. Struktur allozieren 2. Strukturfelder initialisieren 3. Struktur in Arbeitsbereich (Strukturkopie) kopieren 4. Funktionsaufruf mit den bösen Veränderungen machen mittels Übergabe eines Adresszeigers auf die Strukturkopie 5. Glücklich sein, daß die Originalstruktur so bestehen bleibt wie sie vor dem Aufruf der Funktion ausgesehen hat, sprich die Weiterverwendung der ursprünglichen Werte geht durch das Kopieren und Verwenden der Kopie anstatt des Originals in Ordnung mfg Kikakater |
Zitat:
Selbiges würde aber auch für alle anderen Variablen gelten, also warum gibts dann aberhaupt const? Zitat:
Zitat:
Zitat:
2 Strukturen mit den selben Werten, eine zum Arbeiten und eine als Backup erscheint mir nicht zweckmässig. Ein Beispiel: ich hab die Oberstruktur main. Diese enthält ALLE globalen Daten, alles was irgendwie von mehr als einer Funktion des ganzen Programms benutzt werden muß, wie zum Beispiel main.config.{ganzvieleconfigdaten} als auch main.workload.{1000 int variablen die modifiziert werden}. Die funktion funktion(&main.workload,&main.config) modifiziert jetzt die Werte der 1000 int variablen in main.workload. Auf main.config{*.*} wird nur lesend zugegriffen (das kann ich ja selbst bestimmen). Dann wäre es aber schön, wenn man die Configurationsstruktur auch nur lesbar übergeben kann. (wie beim öffnen einer Datei, da kann ich ja auch aussuchen, ob r_only, rw, usw). Mit 2 Strukturen könnte ich anschliessend mainkopie.config nach main.config kopieren. So bleibt meine Konfiguration zwar sicher erhalten, da ja alle Modifikation in main.config überschrieben werden (wohlgemerkt, ich würde main.config nicht bewußt in der Funktion modfizieren. Prinzipiell ist es aber ein Sicherheitsrisiko wenn Konfigurationen von überall modifiziert werden können), aber das ganze wird ziemlich unübersichtlich. (@kikakater: allerdings hatte ich die Idee erst durch das Lesen deines Postings). Und speichersparend ist das auch nicht. |
Wenn schon kopierst du main.config auf mainkopie.config oder ?
Man kopiert doch in Richtung Kopie und nicht umgekehrt ? Der Smilie und *seufz* als Bemerkung geht Richtung C, und nicht an Dich für Dein Nachfragen ;) So ist das gemeint. Du kannst Sie ja lesend übergeben nur stehen dann 2000 Bytes am Stack und müssen von dort wieder entfernt werden (Call by Value mit Zusatz const bezogen auf "Datenfeld" - in diesem Fall Struktur - ."config" (zu Struktur "main" zugehörig). Nach dem Aufruf der Funktion die Kopie auf das Original zu kopieren und zu behaupten, daß die Originalwerte erhalten bleiben ist Veräppelung aber sonst schon gar nichts. Im Übrigen wird die Technik des Versorgens eines Arbeitsbereichs aus einem Originalbereich in der Praxis bei Softwarefirmen sehr wohl verwendet und ist oftmals notwendig um Seiteneffekte (eben das unabsichtliche Überschreiben von Datenfeldern) im Originalbereich, der innerhalb des RAM Speichers gelegen ist, von vornherein auszuschliessen. Dies ist Profialltag, also was solls. Gehirn anstrengen - gut und schön - es gibt aber keinen Schutz vor gewollter Veränderung der Werte, das ist ein Widerspruch in sich. Wenn Du einen Einkauf machst musst Du alle Posten zusammenzählen. Ebenso verhält es sich beim Programmieren (schützenswerte Originalstruktur oder -record im Fall von Pascal etc. und veränderbrae temporäre Strukturkopie). Das ist Programmieren, der Kunst Zügel anzulegen ist das Argument hier nicht. Es handelt sich um "künsteln" und außerdem sollte die Kunst des Programmierens auf das Einhalten von Programmiernormen sich einschränken = täglich gelebter Alltag. Eine Originalstruktur, die verändert werden darf oder muss, braucht selbstnafreilich keine Kopie um an Ihre sie zu verändernde Funktion übergeben zu werden. |
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Auf die Gefahr hin, das ich nerve weil ich mich wiederhole: main.config -> wird am Anfang inititalisiert, und nachher NUR mehr gelesen. main.workload ist das zu bearbeitende Unterelement. Kopie mach ich natürlich von der ganzen main Struktur. Und da ist main.workload auch dabei. (oder?? Vielleicht macht es mehr Sinn Unterelemente wie .config zu Kopieren, und die Kopie zu übergeben. Das erfordert aber, bei realistischeren Strukturen als meine main, viel Disziplin um einen überscihtlichen Code zu erzeugen) Hey, aber Danke für die Anregungen, hilft mir sehr! |
Schutz vor Überschreiben geht bei der Programmausführung nur durch das Anlegen und Versorgen einer Kopie.
Du postest weder die Struktur(en) selbst (struct .... { } ; ) noch hältst Du Dich sonst irgendwie mit Klarheiten auf. Schreib doch einfach: 1) main.config -> mainkopie.config bzw. kopieconfig (letzteres vermute ich eher) 2) Funktionsaufruf mit (&kopieconfig) 3) Glücklich, daß main.config erhalten geblieben ist Variante A: Du solltest bei so grossen (vermute ich) Strukturen, den ganzen Bereich als Übergabebereich wählen und config und workload fix als Variablenfelder (=Strukturvariablenfelder) einplanen. Nämlich insofern, daß der Bereich (also die Struktur) "main" als & (address of) "main" übergeben wird und config und workload entsprechend ihrer auszulesenden und zu verändernden Bedeutung bekannt sind. Zu verändernde Strukturen wie workload kopierst Du dann INNERHALB der Funktion in dynamisch angeforderten Speicher. Variante B: Das beste ist und bleibt aber folgendes: Schreibe eine Wrapper(=Hüll)funktion, die .workload in local_workload kopiert und local_workload sowie main als Adresszeiger auf ihre Bereiche annimmt. Also: Funktion Wrapperfunktion(struct xy_config *pconfig, struct xy_workload *pworkload): 1) struct xy_workload local_workload; // steht am Stack, deswegen besser als dynamischer Speicher, Stichwort Garbage Collection immer wieder notwendig wegen Speicherlücken 2) kopieren *pworkload in local_workload 3) Aufruf: Arbeitsfunktion(pconfig,&local_workload); 4) *pworkload (falls so verwendet ist das main.workload) bleibt erhalten, local_workload ist vielleicht verändert, je nachdem was in der Funktion Arbeitsfunktion passiert. Dein Aufruf lautet also dann: Wrapperfunktion(&main.config,&main.workload); Sollte das beste sein, was nicht nur C, sondern ein Algorithmus überhaupt "hergeben" kann. In Zukunft rufst Du nurmehr Wrapperfunktion(...) auf anstatt Arbeitsfunktion. Und zwar deswegen, weil workload erhalten bleiben soll. Soll config erhalten bleiben und es besteht die Gefahr, daß die Funktion Arbeitsfunktion(...) diesen Parameterblock verändert, muss halt eine Kopie von config gemacht werden und diese lokale Kopie per Adresszeiger an die Funktion übergeben werden. mfg Kikakater |
Danke für den Input.
Ich hab absichlich jeglichen Code vermieden. Ich glaube sprachlich läßt sichs universeller umsetzen. Ausserdem handelt es sich dabei um ein gedankliches Konstrukt ich hab hier nichts vor mir liegen, das main, main.config oder sonst irgendwas ist. main.workload ist nicht relevant. Die Daten werden bearbeitet und sollen bearbeitet werden, anhand von Information aus main.config, welches die Daten enthält, die konfigurieren, wie main.workload bearbeitet wird. D.h. main.workload zu kopieren ist uninteressant, main.config ist das schützenswerte. Aber das so auf deine Wrapperfunktion umzumünzen sollte so schwer nicht sein. Ziel der Funktion ist es ja nur, Konstanten (wie bestimmte Strukturteile usw.), die nicht von Arbeitsfunktion verändert werden soll (egal ob sies jetzt theorethisch könnten oder nicht), zu kopieren, und den Pointer auf die Kopie zu übergeben, was ca dem entspricht was mir eh schon vergeschwebt ist. Das alles allerdings auch noch übersichtlich zu halten wird schwer, vielleicht fällt mir noch was anderes ein. thx |
Bitte :)
Viel Erfolg weiterhin ... |
Alle Zeitangaben in WEZ +2. Es ist jetzt 04:26 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
© 2009 FSL Verlag