Forum: Mikrocontroller und Digitale Elektronik Funktionspointer array als parameter übergeben


von µCFrage (Gast)


Lesenswert?

Hi all,
ich bin gerade zu doof ein funktionsarray als Parameter zu übergeben.
Google hat mir leider nur mit einem einzigen funktionspointer helfen 
können:

Hier der code:
1
typedef void (*stateArray)(void);
2
3
uint8 getArrSize(void);
4
void start0(void);
5
void start1(void);
6
void start2(void);
7
void start3(void);
8
void start4(void);
9
10
stateArray myStateArray[]=
11
{
12
  start0,
13
  start1,
14
  start2,
15
  start3,
16
  start4,
17
};
18
19
int main (void){
20
  uint8 fpSize= getArrSize(/* hier soll die übergabe rein*/);
21
}
22
23
uint8 getArrSize( void){
24
  return sizeof(myStateArray) / sizeof(myStateArray[0]);
25
}

wie ihr seht hab ich es bisher durch eine globale variable gelöst.
Das geht doch aber auch mit einer übergabe?
In etwa so:
1
uint8 fpSize= getArrSize(stateArray nFct){
2
  return sizeof(nFct) / sizeof(nFct[0]);
3
}

Leider leider mag das aber der compiler nicht :\

Danke und Gruß
µCFrage

von Karl H. (kbuchegg)


Lesenswert?

µCFrage schrieb:

> wie ihr seht hab ich es bisher durch eine globale variable gelöst.
> Das geht doch aber auch mit einer übergabe?

Ein Array aus Funktionspointern ist auch nur ein Array wie jedes andere.
Aber: Innerhalb der Funktion ist das Array nicht mehr als C-Array 
'vorhanden' sondern du hast nur einen Pointer auf das erste Element des 
Arrays.
-> Eine Funktion kann prinzipiell mittels sizeof nicht ermitteln, wie 
groß ein Array ist, von dem sie einen Pointer auf den Anfang bekommen 
hat. Die Funktion kann noch nicht mal feststellen, ob der Pointer 
überhaupt auf ein Array zeigt, oder auf ein einzelnes Element

1
void foo( int * pI )
2
{
3
  // hier ist nicht feststellbar, ob pI auf ein int Array
4
  // zeigt, oder auf einen einzelnen int
5
  // Beides ist möglich
6
7
}
8
9
int main()
10
{
11
  int valA[5];   // ein Array von int
12
  int j;         // ein einzelner int
13
14
  foo( valA );   // ist korrekt
15
  foo( &j );     // ist ebenfalls korrekt
16
}

und mit einem Array aus Funktionspointern ist das auch nicht anders.


>
1
> uint8 fpSize= getArrSize(stateArray nFct){
2
>   return sizeof(nFct) / sizeof(nFct[0]);
3
> }
4
>
>
> Leider leider mag das aber der compiler nicht :\

Logisch, denn

    ....       (stateArray nFct)

das ist nun mal kein Pointer, sondern ein einzelnes stateArray Objekt 
(welches trotz seines Namens ja kein Array ist). Wie willst du daher 
davon das Element [0] nehmen?

Nur weil du deinem mittels typedef erzeugten Datentyp einen Namen 
gegeben hast, in dem 'Array' vorkommt, ist es das ja noch lange nicht. 
Das Array hast du ja erst hier
1
stateArray myStateArray[]=
2
{
3
  ...

erzeugt. Du kannst 'stateArray' ja auch durch 'SchnurdirBur' austauschen
1
typedef void (*SchnurdirBur)(void);
2
3
...
4
5
SchnurdirBur myStateArray[]=
6
{
7
  start0,
8
  start1,
9
  start2,
10
  start3,
11
  start4,
12
};
13
14
uint8 fpSize= getArrSize(SchnurdirBur nFct){
15
  return sizeof(nFct) / sizeof(nFct[0]);
16
}

dann wirds vielleicht etwas klarer, dass du innerhalb der Funktion erst 
mal kein Array hast, sondern eben ein SchnurdirBur-Objekt.

Aber wie gesagt: selbst wenn, würde dir das nichts helfen. Denn der 
Übergabemechanismus eines Arrays sieht nun mal so aus, dass die 
Startadresse des Arrays übergeben wird. Und das hilft dir nichts um die 
Größe des Arrays festzustellen.


1
#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
2
3
....
4
5
6
int main()
7
{
8
  uint8 fpSize = ARRAY_SIZE( myStateArray )
9
}

und das ganze funktioniert nur dann, wenn myStateArray dann auch 
tatsächlich als Array sichtbar ist. Hier ist es das.
So ....
1
void foo( stateArray* fnctns )
2
{
3
   ...
4
}
.... ist es das nicht. Da ist es bereits zu einem Pointer degeneriert.

von Karl H. (kbuchegg)


Lesenswert?

Und PS:
Du solltest das hier
1
typedef void (*stateArray)(void);

besser
1
typedef void (*stateFnct)(void);
(ausgesprochen: State-Function) oder
1
typedef void (*stateFnctPtr)(void);
(ausgesprochen: Pointer auf eine State Function)
nennen. Denn genau das ist dieser Datentyp: Er beschreibt einen Pointer 
auf eine State Function. Das du daraus dann ein Array baust
1
stateFnctPtr myStateArray[]=
2
{
3
  start0,
4
  start1,
5
  start2,
6
  start3,
7
  start4,
8
};
ist zwar nett, ändert aber nichts daran, dass der Datentyp eines 
einzelnen Array Elements ein Pointer auf eine bestimmte Art von 
Funktionen ist.

Ein int wird auch nicht zu irgendetwas anderem, nur weil du
1
int werte[] = { 1, 2, 3, 4 };
mehrere int in ein Array verpackst. Ein einzelnes Array-Element ist nach 
wie vor ein int. Und bei dir ist ein einzelnes Array-Element nach wie 
vor ein Pointer auf eine Funktion.

von Wusel D. (stefanfrings_de)


Lesenswert?

Im compilierten Programm ist ein Array eine Ansammlung von Datensätzen 
mit fester Größe (in Deinem Fall Pointer auf Funktionen). Wie viele 
Datensätze das Array groß ist, steht im Array selbst nicht drin.

Das ist ein elementarer Unterschied zu einigen anderen 
Programmiersprachen, z.B. Java. In Java kannst Du jedes Array fragen, 
wie groß es ist. In C geht das nicht.

sizeof(array) erzeugt KEINEN Programmcode, denn sizeof() ist keine 
Funktionen, sondern ein Makro. Das Makro wird VOR dem Compilieren 
aufgelöst. Der Compiler sieht an dieser Stelle nur noch eine konstante 
Zahl.

Daher muss die Größe von array schon vor dem Compilieren feststehen, 
also am Quelltext ablesbar sein.

In Deinem Fall wird das Array als Parameter übergeben. Es handlet sich 
also nicht mehr um ein einziges fixes Array, sondern man könntes 
theoretisch jedes beliebige Array übergeben. Der Comiler prüft zwar den 
Typ der Datensätze, aber nicht die Größe. Du kannst mal ein Array mit 10 
Datensätzen übergeben, und dann ein anderes Array mit 5 Datensätzen.

Daher kann die Größe erst zur Laufzeit des Programmes ermittelt werden. 
Arrays wissen aber nicht, wie groß sie sind.

Die übliche Lösung in solchen Fällen ist, dass man ein Array als 
Parameter übergibt, und zusätzlich einen Integer, der angibt, wie groß 
das Array ist.

Bei der Objektorienterten Programierung ist das einfacher. Da könntest 
Du das Array durch ein Objekt ersetzen, dass (wie auch immer) mehrere 
Datensätze (in Deinem Fall Funktionspointer) speichert. Das Objekt 
könnte weiterhin wissen, wieviele Datensätze es enthält und wie viele es 
maximal enthalten kann.

Bei Mikrocontrollern würde ich auf C++ verzichten. Das Konzept der 
Objektorientierten Programmierung lässt sich allerdings auch in C 
anwenden - nur etwas umständlicher.

Anstelle des Arrays könntest Du zum Beispiel eine Struktur als Parameter 
übergeben, die das Array UND einen Integer (Größe des Arrays) enthält.

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
Noch kein Account? Hier anmelden.