PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Parameter von Funktionen in Funktionen



hosti
27.10.2009, 22:11
Guten Abend,
Ich habe Funktionen in denen ich Funktionen aufrufe.

Die Parameter der in der Funktion aufgerufenen Funktionen muss ich ja der ersten Funktion übergeben.
Nur leider hat jede Funktion schon einige Parameter, dadurch summiert sich das ja stark auf.
Sprich die erste Funktion kann z.B. 10 Parameter haben.
Das ist extrem unübersichtlich und verwirrend.

Gibt es dazu eine andere Lösung?



Funktion(par1, par2, par3, par4, par5, par6, par7....)
{
funk1(par1, par2, par3);
funk2(par2, par4, par5);
funk3(par6, par7);
funk4(par...);
}

Ich hoffe es ist verständlich was ich meine :)

askazo
28.10.2009, 06:59
Du könntest eine Struktur erstellen, in der alle Parameter schön sortiert enthalten sind. Dann brauchst Du der Funktion nur noch einen Zeiger auf diese Struktur zu übergeben.

z.B.


typedef struct {
par1[3];
par2[3]
par3[2];
...
} Parameters ;

void Funktion(Parameters *FktParam)
{
funk1(FktParam->par1);
funk2(FktParam->par2);
funk3(FktParam->par3);
...
}

int main(coid)
{
Parameters myParam;

myParam.par1 = {1,2,3};
myParam.par2 = {4,5,6};
myParam.par3 = {7,8,9};
...

Funktion(&myParam);
}

Alternativ würde sich auch ein 2-dimensionales Array anbieten.

Gruß,
askazo

recycle
28.10.2009, 07:17
Ich habe zwar keine grosse Ahnung von Programierung, aber rein logisch würde ich vermuten, dass es da keine grosse Alternative geben kann.
Wenn eine Funktion wie in deinem Beispiel 7 Parameter benötigt, wird man sie ihr wohl auch geben müssen.
Ausnahme wäre, wenn diese Parameter teilweise so voneinander abhängig sind, dass man sie innerhalb der Funktion berechnen kann. Aber dann wäre die Funktion wohl einfach nur schlecht gemacht.

Ein bischen Hilfestellung bei Funktionen mit vielen Parametern geben bessere IDEs dadruch, dass sie schon beim Eingeben Anzeigen welche Parameter erwartet werden und überprüfen ob hier wenigstens die richtigen Datentypen eingegeben werden.

Hubert.G
28.10.2009, 09:43
Eine Möglichkeit wäre noch globale Variable, jede Funktion hat darauf Zugriff.

hosti
28.10.2009, 11:27
Globale Variablen waren auch mein Gedanke, nur wen ich z.B. folgende Dateien habe:

main.c
funkt.c
funk.h
output.c
output.h

und ich in funk.h Variablen deklariere und dies dann in output.c verwenden will (als Parameter einer Funktion). Klappt das nicht das der Funktion diese Variablen unbekannt sind.
Das verwunder mich, da ich meinte alle nicht anderweitig definierten Variablen sein global. Wen ich sie als Parameter mitübergebe funktioniert es.

Ein Array wollte ich vermeiden den da wird es wirklich unübersichtlich.
Eine Struktur wäre aber eine option

askazo
28.10.2009, 11:51
Variablen solltest Du nie in Header-Dateien verwenden.
Die sollten immer in der entsprechenden C-Datei definiert werden.

Wenn Du globale Variablen in verschiedenen Dateien verwenden willst, musst Du das Attribut "extern" verwenden.

z.B. Deklarierst Du in der Datei funk.c eine Variable:
int meineVariable;

wenn Du diese Variable dann auch in der output.c verwenden willst, musst Du sie dort so bekannt machen:
extern int meineVariable;


Alternativ kannst Du das
extern int meineVariable;
auch in die funk.h packen und diese dann in der output.c includieren.
Das ist sogar die bessere Variante - bin gerade erst beim rumstöbern zu dem Thema drauf gestossen


Gruß,
askazo

ikarus_177
28.10.2009, 11:53
Hi,

ich hätte auch noch eine Frage, die gut zum Thema passen würde: was ist von der Schnelligkeit der Abarbeitung des Programms im Microcontroller sinnvoller/besser: den Funktionen die Variablen ganz "normal" übergeben, oder eher mit Pointern arbeiten?

Meine Funktionen brauchen ebenfalls einige Parameter (vorwiegend Arrays), was wäre da sinnvoller?

Viele Grüße

askazo
28.10.2009, 12:05
In der Regel wird durch die Verwendung von Pointern ein schnellerer Code erzeugt. Aber Vorsicht: es gibt einen grundlegenden Unterschied zwischen einem Funktionsaufruf mit Pointer und dem mit "normaler" Übergabe:

Wenn Du ganz normal die Variable an die Funktion übergibst, kannst Du innerhalb der Funktion mit der Variable machen, was Du willst. D.h. Du kannst sie verändern, ohne dass die aufrufende Funktion das mitbekommt.

Wenn Du einen Pointer auf die Variable an die Funktion übergibst und die Variable innerhalb der Funktion änderst, ändert sich die Variable auch in der aufrufenden Funktion.

Gruß,
askazo

thewulf00
28.10.2009, 13:17
@Ikarus: Pointer sind schneller.
Und eine Array-Übergabe ist nur per Pointer möglich.

hosti
28.10.2009, 16:13
Variablen solltest Du nie in Header-Dateien verwenden.
Die sollten immer in der entsprechenden C-Datei definiert werden.

wenn Du diese Variable dann auch in der output.c verwenden willst, musst Du sie dort so bekannt machen:
extern int meineVariable;


Alternativ kannst Du das
extern int meineVariable;
auch in die funk.h packen und diese dann in der output.c includieren.
Das ist sogar die bessere Variante - bin gerade erst beim rumstöbern zu dem Thema drauf gestossen




Ich habe mich glaub falsch ausgedrückt. In der Header steht z.B.

uint8_t var;
Im Sourcefile

var = 55;
var++;
....

Ich müsst mich jetzt schwer irren aber ich mache das seit Jahren so und meinte dies auch so gelernt zu haben?

Danke für eure Tips

@ikarus
Arrays werden immer mit Pointer in eine Funktion übergeben.

void funk(uint8_t *pos);
funk(pos); ;)

CodeBrowser
28.10.2009, 16:26
Noch eine kleine Anmerkung zur Laufzeit von Pointer vs. "Normal"

Bei der übergabe "by reference", also per Pointer, ist zu beachten dass man in der Regel nur einen Performance-Gewinn hat, wenn keine sog. primitiven Datentype wie int, char o.ä. übergeben werden. Z.B. ist bei einem 32 Bit System der Pointer auch immer 32 Bit. Daher macht es hierbei keinen unterschied. Zumindest in Bezug auf die Performance.

Allerdings sollten z.B. Strukturen immer "by reference" übergeben werden. Da ansonsten die gesamte Struktur auf den Stack kopiert werden muss. Und das kostet Zeit und Speicherplatz.

Soll eine Funktion aber z.B. mehr als einen Rückgabewert besitzten, so muss dies über Pointer oder in C++ über Referenzen geschene. Mit einem C++ Compiler wäre es auch möglich, eine "const reference" zu übergeben. Dadurch verhindert man ein unbeabsichtiges Verändern eines übergebene Parameters.

In jedem Fall kann z.B. ein Blick in den vom C-compiler erzeugten ASM-Code nicht schaden. Es Test mit einem Parameter "by value" (also "normal") und "by reference" sollte die unterschiede klar machen. Den erzeugten ASM Code kann man sich über einen Command-Line-Switch vom Compiler erzeugen lassen.

Gruß
Andy

CodeBrowser
28.10.2009, 16:31
Noch eine kleine Anmerkung:


Ich müsst mich jetzt schwer irren aber ich mache das seit Jahren so und meinte dies auch so gelernt zu haben?

Wenn du wirklich im .H File die DEFINITION der Variable, also "uint8 someVar;" stehen hast, dann ist das eher sehr ungünstig. In einem Header-File sollte immer nur die DEKLARATION einer Variable stehen.

Das heißt:
im .c File steht
uint8 someVar;

imt .h File steht:
extern uint8 someVar;

Damit ist die Variable im C-File DEFINIERT und im H-File DEKLARIERT. Dann sind Compiler und Linker glüklich und man hat sauberen Code der keine Probleme macht. Es kann schnell passieren, wenn die Variable im h-File Definiert wird, dass man Fehlermeldung über doppelt definierte variablen bekommt. Das mag meistens der Linker nicht.

Gruß
Andy

hosti
28.10.2009, 16:38
hm, dann mach ich das ja wirklich falsch :)

Aber meist hab ich ja nur definitionen wie uint8_t var;
was kommt den in den Header ausser der Funktionsprototypen?

z.B. volatile deklarationen?

CodeBrowser
28.10.2009, 16:46
Wie du schon selbst geschrieben hast "...deklarationen"

In einem Header File sollten immer nur Deklarationen stehen. Dabei ist es egal, ob es sich um Funktions-, Klassen-, Struktur-, Typ-, oder Variablen-Deklarationen handelt.

Aber auch Konstanten und Präprozesormakros kommen in ein h. File. Alles andere sollte in ein .c File.

hosti
28.10.2009, 16:47
uiuiui, ich hab mir gerade ein paar meiner Uraltcodes angesehen.
Dort hab ichs richtig gemacht. 4Jahre C abstinenz waren doch nicht so klug.

Vielen dank für den Hinweis

thewulf00
28.10.2009, 16:48
Ich stimme CodeBrowser zu, mit der Anmerkung, dass die Übergabe eines Pointers auf einem AVR länger dauert, also die Übergabe eines 8-Bit-Primitives (uint8_t, char, ...), denn die Pointer sind 16bit breit.

@Hosti
Außerden Funktionsprototypen kommt in den Header noch allerlei Definitionen:
- defines
- extern-variablen
- einbindung anderer Header.

CodeBrowser
28.10.2009, 16:53
Das mit dem AVR und 16-Bit Pointer wusste ich nicht, da ich bisher die AVR Controller nicht verwendet habe. Aber spätestens bei der Analyse des ASM Codes hätte man das gesehen ;-)

hosti
28.10.2009, 17:11
Ich habe jetzt einmal einen Teil angepasst.
Doch es kommt eine Fehlermeldung das die Konstante a zweimal definiert ist.

funk.h

const unsigned short a = 1234;
Im Sourcefile wird a einfach als Parameter übergeben.

Ist die definition/deklaration im header falsch?

CodeBrowser
28.10.2009, 17:30
Da sollte noch ein extern davor.
Ich bin mir jetzt mit dem Syntax bei Konstanten nicht so sicher, aber ich glaube das müsste so ein:

.h File
extern const unsigned short a; // Deklaration

und im C-File
const unsigned short a = 1234; // Definition

hosti
28.10.2009, 17:34
Das extern ist kein muss oder?, nur wen ich es in einer Funktion ohne Parameter übergabe verwenden will, oder hab ich das falsch verstanden?

CodeBrowser
28.10.2009, 17:42
Das extern sagt dem Compiler, dass es sich hierbei nur um eine Deklaration handelt. Denn ansonsten wäre der Syntax für Deklaration und Definition einer gloaben Variable der gleiche.

Sobald du eine globale Variable in mehr als einem .c File verwenden willst, musst du die Variable mit extern im .h File Deklarieren und in EINEM C-file definieren.

Verwendest du die globale Variable aber nur innerhalb einer .c-Datei, dann brauchst du in dem Header File gar nichts machen. Dann reicht die globale Definition in dem C-File in dem du die Variable verwenden willst. Natürlich muss die Definition der Variable in dem C-File dann vor der ersten Verwendung erfolgen

Ich hoffe ich habe dich jetzt nicht ganz verwirrt? ;-)

thewulf00
29.10.2009, 07:29
Wenn Du in einem AVR eine CONST verwendest, dann nimm doch gleich #define, das ist unterm Strich egal, da das Const wahrscheinlich wegoptimiert wird. Ein define kann man aber im Header machen, und somit ohne extern usw. überall benutzen.
#defines werden vom Precompiler in die genutzen Stellen eingesetzt, so dass der Compiler die defines garnicht mehr sieht, sondern nur noch das Eingesetzte.

Wenn Du unbedingt auf den Typ bestehst, dann Caste es im define:

#define a ((uint8_t)1234)

CodeBrowser
29.10.2009, 09:37
Hmm, dass halte ich für einen nicht ganz so sauberen Weg. Auch wenn das const "Weg-optimiert" wird, so bietet es dem Compiler eine Zusatzinformation über den Typ und kann so die Überprüfungsmöglichkeiten des Compilers erhöhen.

Bei uns sind z.B. in den Richtlinien für embedded Software Präprozessormakros (da gehören Defines für Konstanten auch dazu) verboten.

Aber letztendlich ist das ein Thema über das man glaube ich ewig philosophieren kann ;-)