Forum: PC-Programmierung Frage zu STM32F429 und C/C++


von Michael (Gast)


Lesenswert?

Hallo Zusammen,

habe eine Frage zum STM32F429. So wie ich verstanden habe, gibt es Libs, 
die von privat auf verschiedenen Webseiten hochgeladen werden. Als C++ 
Programmierer hab ich da aber ein Problem.

In meinem Code werden folgende Parameter gefragt: int sprintf ( char * 
str, const char * format, ... );

Dachte in C gibt es keine Zeiger? Und wenn, warum schreibe ich dann 
"sprintf (buffer, "%d plus %d is %d", a, b, a+b);" ohne Adressoperator 
vor der buffer-char?

Zweitens habe ich eine andere Funktion, bei der ebenfalls der Zeiger 
einer Variablen erwartet wird, als Parameter übergebe ich dann das hier:

UB_Font_DrawString(10,70,"Pressed 
,&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);

Hier wird vor dem Arial-Font der Adressoperator verwendet?!?! Bin 
verwirrt.

von Peter II (Gast)


Lesenswert?

Michael schrieb:
> Dachte in C gibt es keine Zeiger?

wie kommst du darauf. Bei C und C++ gehören schon immer Zeiger zur 
Sprache.

Michael schrieb:
> Dachte in C gibt es keine Zeiger? Und wenn, warum schreibe ich dann
> "sprintf (buffer, "%d plus %d is %d", a, b, a+b);" ohne Adressoperator
> vor der buffer-char?

weil es C ist, und Arrays(strings) immer also Zeiger übergeben werden.

Michael schrieb:
> UB_Font_DrawString(10,70,"Pressed
> ,&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);

kann alles mögliche Bedeuten, da das " kein Gegenstück hat.

von Ben W. (ben_w)


Lesenswert?

Michael schrieb:
> Dachte in C gibt es keine Zeiger? Und wenn, warum schreibe ich dann
> "sprintf (buffer, "%d plus %d is %d", a, b, a+b);" ohne Adressoperator
> vor der buffer-char?

C hat genauso Zeiger wie C++
was du vermutlich meinst sind Referenzen, die in deinem Beispiel ja auch 
überhaupt nicht benutzt werden, sondern schlichtes call-by-value ...

von Michael (Gast)


Lesenswert?

Also übergebe ich char bzw. Arrays immer ohne Adressoperator? Und was 
ist mit dem Adressoperator bei meinem Beispiel mit der Schriftart? Ist 
doch auch ein string.

von Dr. Sommer (Gast)


Lesenswert?

In C *genau wie in C++* werden Arrays grundsätzlich als Pointer 
übergeben, daher ist der Adressoperator dort überflüssig und darf dort 
nicht verwendet werden. Bei deinem "&Arial_11x18" - Beispiel, wenn 
Arial_11x18 ein char* ist, übergibst du die Adresse der Adresse, also 
einen Doppelpointer (char**).

von Michael (Gast)


Lesenswert?

Das muss ich mir nachher noch einmal genauer anschauen.

Eikne Frage noch.

Struct adres
{

};

Ist eine Struktur vom Datentyp adres. enn ich bei einer Funktion eine 
Struktur als Ruckgabewert habe, warum wird das dan so geschrieben:

Struct adres *ptr_Adresse ()
{
}

Ich dachte immer, dass der Ruckgabetyp dem Datentyp entsprechen muss und 
mein Datentyp ist adres, warum wird aber überall struct vor der Funktion 
gesetzt, wenn doch adres der Datentyp ist?

Wenn ich beispielsweise Klassen als Parameter übergebe, gebe ich auch 
nur den Klassentyp und en Namen der Klasse z.B. Funktion(myklass 
Klasse1) ohne das class davor. Danke

von Peter II (Gast)


Lesenswert?

Michael schrieb:
> warum wird aber überall struct vor der Funktion
> gesetzt, wenn doch adres der Datentyp ist?

weil in c der Datentype nunmal ein "struct xx" ist. Erst bei späteren 
Versionen (C99??) oder C++ darf man das struct weglassen.

von nop (Gast)


Lesenswert?

Peter II schrieb:
> weil es C ist, und Arrays(strings) immer also Zeiger übergeben werden.
Man könnte auch die Adresse auf das erste Element übergeben.
Macht zwar keiner, aber vllt. trägt es zum Verständnis bei.
1
&myArray[0]

Peter II schrieb:
> Versionen (C99??) oder C++ darf man das struct weglassen.

Oder über typedef:
1
typedef struct
2
{
3
int a;
4
int b;
5
}tMyStructType;

von Michael (Gast)


Lesenswert?

Vielen Dank. Das hast mir sehr geholfen.

von Michael (Gast)


Lesenswert?

Hallo nochmal,

hier das Beispiel mit den Pointern:

Funktion: void UB_Font_DrawString(uint16_t x, uint16_t y,char *ptr, 
UB_Font *font, uint16_t vg, uint16_t bg)
{...}

und hier der Aufruf mit Adressoperator: 
UB_Font_DrawString(10,70,"Pressed 
",&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);


UNd hier das zweite Beispiel:

UB_Font_DrawString(10,300,buf,&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);


Warum verwende ich bei meinem char-Array buf kein Adressoperator, aber 
bei Arial_11x18 schon?

von Dr. Sommer (Gast)


Lesenswert?

Weil der bei Arrays entfällt, bei structs aber nicht.

von Michael (Gast)


Lesenswert?

Stimmt, deswegen wurde auch oben gesagt,  dass wenn Arial_11x18 ein char 
Array wäre, ich dann eine Adresse der Adresse übergeben wurde. Da es 
aber kein char Datentyp ist, passt das. Besten Dank.

von Dr. Sommer (Gast)


Lesenswert?

Michael schrieb:
> Da es aber kein char Datentyp ist,
Nochmal lesen. Weil es KEIN ARRAY ist; mit "char" hat das NICHTS zu tun. 
Bei einem "int" array müsstest du auch kein '&' eingeben.

Michael schrieb:
> Als C++ Programmierer hab ich da aber ein Problem.
Mehr als Hello World kannst du da aber auch nicht programmiert haben...

von Michael (Gast)


Lesenswert?

Also ich denke schon, dass ich richtig liege. Bei einer Struktur wie 
oben übergebe ich die Adresse. Bei einem char entfällt das und ich 
benötige keinen Adressoperator ...

von Dr. Sommer (Gast)


Lesenswert?

Michael schrieb:
> Also ich denke schon, dass ich richtig liege.
Bitte, wenn du das denkst. Der C++ Standard denkt aber anders.
> Bei einer Struktur wie
> oben übergebe ich die Adresse.
Ja.
> Bei einem char entfällt das und ich
> benötige keinen Adressoperator ...
Nein, s.o.

von Michael (Gast)


Lesenswert?

Sorry, falsch ausgedrückt. char ist zwar ein Array, aber würde auch für 
einen anderen Datentyp gälten. Ok betrifft Array und nicht char. Habe es 
verstanden :-)

von Dr. Sommer (Gast)


Lesenswert?

char ist kein Array sondern ein einzelnes Zeichen. char[] ist ein Array, 
und char* kann ein Zeiger auf ein Array sein.

von Michael (Gast)


Lesenswert?

Bei mir handelt es sich m char[30], also ein Array. Bin bei Strukturen 
sowieso etwas verwirrt. Derzeit ist mir auch nicht klar, weshalb in der 
lib, auf die ich zugreife, typdef verwendet wird. Ob ich einen neuen 
DatentypBezeichner definiere oder nicht, ich spare mir in _ doch 
hoechstens das struct vor der Erzeugung einer Instanz.

von Dr. Sommer (Gast)


Lesenswert?

Ist doch gut, ein "struct" weniger zu tippen und potentiell zu 
vergessen.

von Uwe B. (derexponent)


Lesenswert?

Michael schrieb:
> Derzeit ist mir auch nicht klar, weshalb in der
> lib, auf die ich zugreife, typdef verwendet wird

die Library (und Seite) ist von mir und wie schon geschrieben schau
einfach in ein C-Buch, da stehen so sachen drinn
1
// das hier erzeugt nur eine Struktur :
2
struct s1 {
3
  char a;
4
};
5
6
// zum benutzen muss eine Variable deklariert werden (mit struct)
7
struct s1 v1;
8
9
// der Zugriff erfolgt dann per
10
v1.a=5;

dann gibt es noch eine verkürzte Schreibweise :
1
// das erzeugt eine Struktur und legt gleich noch eine Variable davon an
2
struct s1 {
3
  char a;
4
}v1;
5
6
// der Zugriff erfolgt dann per
7
v1.a=5;

und ich verwende in meinen Beispielen wieder was anderes :
1
// das hier erzeugt nur eine Struktur :
2
typedef struct s1{
3
  char a;
4
}s1;
5
6
// zum benutzen muss eine Variable deklariert werden (ohne struct !!)
7
s1 v1;
8
9
// der Zugriff erfolgt dann per
10
v1.a=5;

...ich sollte doch noch ein Buch schreiben :-)

UB

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Uwe B. schrieb:
> ...ich sollte doch noch ein Buch schreiben :-)
Wir brauchen hier lediglich eine Forum-Funktionalität in der man auf 
Knopfdruck den Text zu einem Standardproblem schreibt... 
Anfangsvorschläge:
* Compiler&Linker Optionen in eclipse & CoIDE eingeben
* typedef struct
* float ohne FPU
* Programmer tut nicht
etc.

Bücher in denen das alles steht gibts ja schon zuhauf, aber diese Fragen 
kommen trotzdem alle 2 Tage...

von Michael (Gast)


Lesenswert?

Ok, danke für den Hinweis. Zum Thema Adressen und char nochmal: char ist 
ja nicht ARRAY, wie vorher diskutiert wurde. Aber irgendwie ist doch 
jeder char ab 1 Zeichen doch ein Array oder nicht?

ftk (char *ptr) wartet auf einen Zeichensatz, in dem Fall beispielsweise 
"ERROR", Hier verwende ich ja keinen Adressoperator, genau wie bei allen 
anderen Strings ja auch. Oder bin ich jetzt total falsch?

von Pete K. (pete77)


Lesenswert?


von Michael (Gast)


Lesenswert?

Ich habe Bücher, aber bin verwirrt.

Bei void Funktion(int *ptr) übergebe ich die Adresse einer Variable mit 
&.

Bei voi Funktion (char *ptr) mache ich das ohne Adressoperator.

Aber weiter oben wurde gesagt, dass es allgemein für Arrays gilt, dass 
da kein Adressoperator vorangestellt wird. Aber void Funktion (int 
*ptr[2]) habe ich auch noch nicht gesehen. ???

von Michael (Gast)


Lesenswert?

Habe es jetzt mal so getestet:
1
void Funktion(int ptr[])
2
{
3
  cout << *ptr << endl;
4
  
5
};
6
7
8
int main ()
9
10
{
11
  int Punkte[2];
12
13
  Punkte[0]=100;
14
  Punkte[1]=200;
15
16
  Funktion(Punkte);
17
18
  system("PAUSE");
19
  return 0;
20
}

Daher nehme ich es einfach mal so hin, dass ich Arrays, egal ob char 
oder int oder sonstige ohne Adressoperator übergebe.

Habe es dann so abgeändert:
1
void Funktion(int *ptr)
2
{
3
  cout << *ptr << endl;
4
  cout << ptr[1] << endl;
5
  
6
};
7
8
9
int main ()
10
11
{
12
  int Punkte[2];
13
14
  Punkte[0]=100;
15
  Punkte[1]=200;
16
17
  Funktion(Punkte);
18
19
  system("PAUSE");
20
  return 0;
21
}

Versuche mir das jetzt einfach zu merken. Ich denke mal, dass ich bei 
ptr[1] keinen "*"-Operator benbötige, da ich hier ja durch den Index die 
Zahl an der Adresse bereits anspreche.

: Bearbeitet durch User
von TigerClaw_PCPointer (Gast)


Lesenswert?

Arrays werden immer per Call by reference an Funktionen übergeben und 
die Angaben zur Grösse kannst du in der Parameterliste weglassen, da 
eine Anfangsadresse existiert und über diese alle Elemente erreicht 
werden können. Schau mal bei Google nach openbook C Galileo. Dort kannst 
die alles nachlesen.

von Michael (Gast)


Lesenswert?

Ok, aber wichtig ist, dass in meiner Parameterliste entweder int *ptr 
oder int ptr[] steht.

Also wenn ich ein Array an eine Funktion übergebe mit 
Funktion(MeinArray) muss ich als Parameter void Funktion(int DasArray[]) 
oder aber int *DasArray angeben? Adressoperator brauche ich hier also 
nicht dafür aber muss ich angeben, dass es ein Zeiger sein soll, der auf 
Anfangsadresse des Arrays zeigt?!

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Ok, aber wichtig ist, dass in meiner Parameterliste entweder int *ptr
> oder int ptr[] steht.

Kommt drauf an, was du jetzt mit wichtig meinst.
Wenn du denkst, dass es einen Unterschied macht, ob du die Form "int 
*ptr" benutzt, oder doch lieber "int ptr[]", dann hast du dich 
geschnitten. Beides sind nur 2 verschiedene Schreibweisen für dasselbe.

> Also wenn ich ein Array an eine Funktion übergebe mit
> Funktion(MeinArray) muss ich als Parameter void Funktion(int DasArray[])
> oder aber int *DasArray angeben?

Wie oft denn noch?

Ja. Denn Arrays werden immer an eine Funktion übergeben, in dem die 
Startsdresse des Arrays übergeben wird. Also muss es eine Pointer 
Variable geben, die in der Funktion dann diese Adresse aufnimmt.

> Adressoperator brauche ich hier also
> nicht

Nein.
Der ist bei Arrays implizit. Wird der Name eines Arrays benutzt, ohne 
Indexoperation, dann ist damit automatisch immer die Startadresse des 
Arrays gemeint.
Und das gilt nur und ausschliesslich für Arrays und für sonst nichts 
anderes.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:

> Versuche mir das jetzt einfach zu merken. Ich denke mal, dass ich bei
> ptr[1] keinen "*"-Operator benbötige, da ich hier ja durch den Index die
> Zahl an der Adresse bereits anspreche.

Auch auf die Gefahr hin, dich jetzt noch mehr zu verwirren:

Der Indexoperator ist in C so definiert.
1
  a[i]  ist equivalent zu  *(a + i)

In der Indexoperation steckt also der Dereferenzier-* automatisch mit 
drinnen. Array Indizierung ist in C (und nicht nur dort) in Form von 
Pointer-Arithmetik definiert.

von Karl H. (kbuchegg)


Lesenswert?

> Also wenn ich ein Array an eine Funktion übergebe ...

Wenn man es ganz streng sieht, dann wird ein Array eigentlich überhaupt 
nicht an eine Funktion übergeben.

Du kannst einen int übergeben
1
void foo( int a )
2
{
3
  a = 8;
4
}
5
6
int main()
7
{
8
  int b = 5;
9
10
  foo( b );
11
}

Hier wird beim Funktionsaufruf, der Wert von b genommen und an die 
Funktion übergeben. Dieser Wert wird innerhalb der Funktion an die 
dortige lokale Variable a gebunden. a hat also nach dem Betreten der 
Funktion ebenfalls den Wert 5, weil dieser Wert an die Funktion 
übergeben wurde. Aber ansonsten haben das a in der Funktion und das b in 
main() nichts mehr miteinander zu tun. Die Funktion hat eine Kopie des 
Wertes erhalten.

Und genau dieses, das Übergeben von Werten geht bei Arrays nicht. Und 
zwar nur bei Arrays. Arrays können nicht so übergeben werden.
Was man statt dessen macht ist, dass man der Funktion die Startadresse 
des Arrays übergibt
1
void foo( int * werte )
2
{
3
  werte[0] = 8;
4
  werte[1] = 9;
5
}
6
7
int main()
8
{
9
  int nummern[2] = { 1, 2 };
10
11
  foo( nummern );
12
}

da 'nummern' ein Array ist, und hier der Name des Arrays alleine 
vorkommt (also ohne Indexoperation), ist durch die Nennung des Array 
Namens automatisch die Startadresse des Arrays gemeint. Und genau diese 
Startadresse wird an die Funktion übergeben. Die Funktion fängt diese 
Startadresse in einem dafür geeignetem Datentyp auf, eben einer Pointer 
Variablen.

Der wesentliche Punkt an dieser Stelle ist aber, das die Funktion somit 
Zugriff auf das Array des Aufrufers hat. Die Funktion hat NICHT wie oben 
eine eigene lokale Kopie der Werte, sondern sie benutzt das Array des 
Aufrufers. Ein Beschreiben über die lokale Pointer-Variable 'werte', 
verändert die Inhalte von 'nummern' beim Aufrufer.


Im ersten Beispiel war die Sache so
1
  main
2
3
  b
4
  +------+
5
  |  5   |
6
  +------+
7
8
         Funktionsaufruf, die Variable a wird erzeugt
9
10
                                    a
11
                                   +-------+
12
                                   |       |
13
                                   +-------+
14
15
         und dieser Variablen wird eine Kopie des Wertes
16
         zugewiesen.
17
18
                                    a
19
                                   +-------+
20
        5 .......................> |   5   |
21
                                   +-------+
22
23
        Während die Funktion läuft, existieren 2 Variablen,
24
        jede vom Typ int, die voneiander vollkommen unabhängig sind
25
26
27
  b
28
 +-------+                         a
29
 |  5    |                        +--------+
30
 +-------+                        |  5     |
31
                                  +--------+
32
33
        wird a verändert, dann wirkt das nur auf a und auf sonst nichts
34
            a = 8;
35
36
  b
37
 +-------+                         a
38
 |  5    |                        +--------+
39
 +-------+                        |  8     |
40
                                  +--------+

etwas anders ist der Array-Fall. Denn Arrays werden nicht übergeben. 
Ihre Startadresse wird übergeben
1
Wieder beginnt die Sache mit den Variablen in main. Diesmal aber mit einem Array
2
3
   main
4
5
   nummern
6
   +-------+
7
   |  8    |
8
   +-------+
9
   |  9    |
10
   +-------+
11
12
Im Zuge des Funktionsaufrufs wird in der Funktion die Variable werte erzeugt.
13
14
                                    werte
15
                                    +--------+
16
                                    |        |
17
                                    +--------+
18
19
Diese ist aber ein Pointer ... sie muss ein Pointer sein, denn Arrays
20
werden ja nicht übergeben, indem die Inhalte des Arrays übergeben werden,
21
sondern in dem die Startadresse des Arrays übergeben wird. Nachdem diese
22
Startadresse in werte abgelegt wurde, sieht die Sache also so aus
23
24
                                    werte
25
                                    +--------+
26
+----------------------------------------o   |
27
|                                   +--------+
28
|
29
|  nummern
30
|  +-------+
31
+->|  8    |
32
   +-------+
33
   |  9    |
34
   +-------+
35
36
werte ist zu einem Zeiger geworden, der auf die originalen Inhalte in
37
main() durchzeigt. Würde über 'werte' etwas verändert, sei es über
38
39
               werte[0] = 1
40
41
                                    werte
42
                                    +--------+
43
+----------------------------------------o   |
44
|                                   +--------+
45
|
46
|  nummern
47
|  +-------+
48
+->|  1    |
49
   +-------+
50
   |  9    |
51
   +-------+
52
53
oder sei es über explizite Pointer-Syntax
54
55
                *( werte + 1 ) = 2;
56
57
                                    werte
58
                                    +--------+
59
+----------------------------------------o   |
60
|                                   +--------+
61
|
62
|  nummern
63
|  +-------+
64
+->|  1    |
65
   +-------+
66
   |  2    |
67
   +-------+
68
69
dann wird diese Änderung im original Array des Aufrufers gemacht. Aber zu
70
keinem Zeitpunkt ist jemals eine Kopie des originalen Arrays des Aufrufers
71
gemacht worden.

das unterscheidet Arrays von allen anderen Datentypen in C. Und dieser 
Unterschied gilt nur für Arrays und sonst nichts anderes. Alle anderen 
Dinge, seien es Strukturen, seien es Unions, seien es die primtiven 
Datentypen wie int, float, char, long, .... werden genau wie das erste 
Beispiel in diesem Post behandelt: Beim Aufruf wird eine Kopie des 
Inhaltes gemacht und diese Kopie wird an eine frisch erzeugte Variable 
innerhalb der Funktion gebunden. Nur bei Arrays gibt es diesen 
Mechanismus nicht. Dort muss man immer über den Mechanismus der Übergabe 
der Adresse und einer funktionslokalen Pointer-Variablen gehen. Genauso 
wie man es mit den restlichen Datentypen auch machen muss, wenn man der 
Funktion den Zugriff auf die originale Variable beim Aufrufer 
ermöglichen will, so dass die Funktion nicht mit einer Kopie arbeitet, 
sondern die Variable des Aufrufers ändern kann
1
void foo( int * a )
2
{
3
  *a = 8;
4
}
5
6
int main()
7
{
8
  int k = 7;
9
10
  foo( &k );
11
}

1
   main
2
   k
3
   +-------+
4
   |   7   |
5
   +-------+
6
7
Funktionsaufruf: foo( &k );
8
9
                                   a
10
                                  +-------+
11
+-------------------------------------o   |
12
|                                 +-------+
13
|
14
|  k
15
|  +------+
16
+->|  7   |
17
   +------+
18
19
Zuweisung:  *a = 8;
20
21
                                   a
22
                                  +-------+
23
+-------------------------------------o   |
24
|                                 +-------+
25
|
26
|  k
27
|  +------+
28
+->|  8   |
29
   +------+

und ehe die Frage kommt:
Nein, die Funktion kann für sich alleine nicht entscheiden oder 
feststellen, ob die Adresse die sie bekommt jetzt auf ein Array zeigt 
oder auf eine einzelne Variable. Das ist schlicht und ergreifend der 
Funktion nicht möglich und es obliegt einzig und allein deiner Sorgfalt, 
dass hier nichts schief geht.

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Vielen Dank für die ausführliche Antwort. Mittlerweile hat es auch bei 
mir "Klick" gemacht :) An sich mag das Thema vielleicht nicht so 
schwierig sein, aber manche brauchen eben dann doch länger :)

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.