Forum: Mikrocontroller und Digitale Elektronik Frage zu Zeigern


von Tobi (Gast)


Lesenswert?

Hallo,

Ich habe mehrere globale Variablen.
1
uint8_t var1 = 39;
2
uint8_t var2 = 39;
3
uint8_t var3 = 120;
4
uint16_t var4  = 1252;

Nun sollen diese Variablen einem struct zugeordnet werden (Menüstruktur)
1
struct menuepunkt
2
{
3
  void *name;
4
  void *variable;
5
  void *einheit;
6
};
7
8
struct menuepunkt hauptmenue[] = 
9
{
10
  {&str_var1, &var1, &str_degree},
11
  {&str_var2, &var2, &str_degree},
12
  {&str_var3, &var3, &str_kmh},
13
  {&str_var3, &var4, &str_v}
14
};
Nun mochte ich die Werte auf die die Zeiger der Variablen zeigen 
auslesen.
Normalerweise mache ich das so:
1
uint8_t variable = (uint8_t) var1;

Da meldet der Compiler aber : "cast from pointer to integer of different 
size"

Was mache ich falsch?

Noch eine Frage:
Kann ich irgendwie herausfinden ob var1 als uint8_t oder uint16_t 
definiert ist?

Danke

von R. F. (rfr)


Lesenswert?

Tach!!

Wenn du auf globale Variablen zugreifen willst, solltest du die 
Schreiblesezugriffe sorgfältig planen, zB so:

volatile * const unsigned char var1 = [Adresse]

Nun soll eine Menüstruktur abgebildet werden:

typedef struct manu{
     blafasel m_name;
     blafasel m_var;
     blafasel m_einheit;
}

es gibt eigentlich keinen typ namens blafasel. Hier sollte man etwas 
richtiges einsetzen. Sicer hast du etwas geeignetes auf Lager.

Von diesem Typ kann amn dann alles andere ableiten. Ein neues menüitem 
wird angelegt, indem es von der typedef erzeugt wird und dann mir Daten, 
die über edie zeiger eingelesen werden, gefüllt wird.

Grüsse

Robert

von Ahem (Gast)


Lesenswert?

Also Tobi,

das Grundproblem bei Deiner Frage wird zunächst einmal der folgende Link 
abdecken.
Beitrag ""Hilfe", "funktioniert nicht", funktioniert nicht."

Zusätzlich:

>Nun mochte ich die Werte auf die die Zeiger der Variablen zeigen
>auslesen.
>Normalerweise mache ich das so:
1
uint8_t variable = (uint8_t) var1;

Mit dem obigen Programmtext bekommst Du diesen Fehler garantiert nicht! 
Denn hier gibt es garkeinen cast von einem Zeiger. D.h. Du machst das 
auch nicht "normalerweise" so. Das funktioniert auch schon deswegen 
nicht mit Deinem Array von structs, da weder ein Index noch ein Punkt 
noch ein '*' erscheint.

>Kann ich irgendwie herausfinden ob var1 als uint8_t oder uint16_t
>definiert ist?
Dazu brauchts Du nur Deinen eigenen Programmtext lesen. Warum fragst Du 
das?

von Karl H. (kbuchegg)


Lesenswert?

Tobi schrieb:

> Kann ich irgendwie herausfinden ob var1 als uint8_t oder uint16_t
> definiert ist?

Nein, kannst du nicht. In C gibt es keine Reflection.
Du musst dir in deine Struktur einen entsprechenden Eintrag machen, aus 
dem du den Datentyp rausfindest. In der Verwendung benutzt du dann 
diesen Eintrag um dir den Datentyp des Pointers zurechtzucasten.

Für alle anderen Pointer, bei denen feststeht, auf welchen Typ sie 
zeigen benutzt du keinen void Pointer.
1
#define TYPE_UNKNOWN 0
2
#define TYPE_UINT8   1
3
#define TYPE_UINT16  2
4
#define TYPE_INT8    3
5
#define TYPE_INT16   4
6
#define TYPE_STRING  5
7
8
struct menuepunkt
9
{
10
  const char * name;
11
  const char * einheit;
12
  uint8_t      datatype;
13
  void *       variable;
14
};
15
16
uint8_t    anzahl;
17
uint16_t   drehzahl;
18
int8_t     temperatur;
19
int16_t    hoehe;
20
char       name[80];
21
22
struct menuepunkt hauptmenue[] = 
23
{
24
  { "Drehzahl",   "U/min", TYPE_UINT16,  &drehzahl },
25
  { "Anzahl",     "Stück", TYPE_UINT8,   &anzahl },
26
  { "Name",       "",      TYPE_STRING,  &name },
27
  { "Temperatur", "°C",    TYPE_INT8,    &temperatur },
28
  { "Höhe",       "m",     TYPE_INT16,   &hoehe }
29
}
30
31
#define MENU_LEN  ( sizeof(hauptmenue) / sizeof(*hauptmenue) )
32
33
int main()
34
{
35
  int i;
36
37
  uint8_t  u8Value;
38
  uint16_t u16Value;
39
  int8_t   i8Value;
40
  int16_t  i16Value;
41
  char*    sValue;
42
43
  for( i = 0; i < MENU_LEN; ++i ) {
44
45
    lcd_string( hauptmenue[i].name );
46
 
47
    switch( hauptmenue[i].datatype ) {
48
      case TYPE_UINT8:
49
        u8Value = *((uint8_t *)hauptmenue[i].variable));
50
        utoa( buffer, u8Value, 10 );
51
        lcd_string( buffer );
52
        break;
53
54
      case TYPE_UINT16:
55
        u16Value = *((uint16_t *)hauptmenue[i].variable));
56
        utoa( buffer, u16Value, 10 );
57
        lcd_string( buffer );
58
        break;
59
60
      case TYPE_INT8:
61
        i8Value = *((int8_t *)hauptmenue[i].variable));
62
        itoa( buffer, i8Value, 10 );
63
        lcd_string( buffer );
64
        break;
65
66
      case TYPE_INT16:
67
        i16Value = *((int16_t *)hauptmenue[i].variable));
68
        itoa( buffer, i16Value, 10 );
69
        lcd_string( buffer );
70
        break;
71
72
      case TYPE_STRING:
73
        sValue = (char *)(hauptmenue[i].variable));
74
        lcd_string( sValue );
75
        break;
76
    }
77
78
    lcd_string( hauptmenue[i].einheit );
79
  }
80
}

von Sebastian B. (mircobolle)


Lesenswert?

Die Lösung von Karl heinz Buchegger find ich eigentlich sehr schön!

schön zu verstehen und transparente Vorgehensweise.

Wobei ich mir mit (void*) Pointern immer ein bisschen schwer tue.
(void*) heisst ja nur, leg einen Pointer mit der Adressbreite des 
Mikrocontrollers an, also soweit mir bekannt.

Bei einem 8 Bit System wäre das dann standardmäßig ein Pointer auf einen 
8 Bit Wert. Soweit richtig, oder?

Ist dann sichergestellt, dass, wenn ich auf eine 16 Bit Variable mit 
diesem Pointer zugreife:
1
void * test_pointer; // 8 Bit System
2
3
static uint16_t var_16=500;
4
5
void main (void)
6
{
7
test_pointer = &(var_16); // Erhaelt die Adresse wo die 16 Bit Variable liegt
8
9
(*test_pointer)++; // direkter Zugriff
10
11
// oder
12
13
(*((uint16_t*)(test_pointer)))++; // erst Pointer cast und dann Zugriff
14
15
}


Was würde bei Fall 1 passieren? Hab leider gerade keinen C Compiler zur 
Hand ;-)

Also ich würde denken:
Er behandelt die Variable wie einen 8 Bit Wert:

500 : MSB / LSB : 0x01F4 : 01 F4

Also Ergebnis würde also bei Fall 1: 2 rauskommen?
und bei Fall 2: 501 ?

Gruß

von Tobi (Gast)


Lesenswert?

Danke!

Du hast mir sehr geholfen, auch wenn ich gestern schon sehr wirres Zeug 
geschrieben hab. War schon spät :)

Tobi

von Karl H. (kbuchegg)


Lesenswert?

Sebastian B. schrieb:

> Wobei ich mir mit (void*) Pointern immer ein bisschen schwer tue.

ein void * ist einfach nur ein Pointer, der eine Adresse enthält. Es ist 
aber nicht festgelegt, welchen Datentypen man vorfindet, wenn man den 
Pointer dereferenziert. In diesem Sinne ist ein void Pointer ein 
generischer Pointer.

> Bei einem 8 Bit System wäre das dann standardmäßig ein Pointer auf einen
> 8 Bit Wert. Soweit richtig, oder?

Nein. Ein void Pointer trifft keine Aussage darüber, was an der 
entsprechenden Speicherstelle auf die er zeigt zu finden ist.

> void * test_pointer; // 8 Bit System
>
> static uint16_t var_16=500;
>
> void main (void)
> {
> test_pointer = &(var_16); // Erhaelt die Adresse wo die 16 Bit Variable
> liegt
>
> (*test_pointer)++; // direkter Zugriff

Das geht nicht.
Einen void Pointer kann man nicht dereferenzieren.
Um das tun zu können, muss der Pointer auf einen speziellen Datentyp 
zeigen. void leistet das nicht.


> (*((uint16_t*)(test_pointer)))++; // erst Pointer cast und dann Zugriff

so gehts.
Du hast aus dem generischen 'Ich zeige auf irgendwas' Pointer einen 
Pointer gemacht, der auf einen uint16_t zeigt.

> Was würde bei Fall 1 passieren?

Gar nichts, du kriegst das nicht durch den Compiler.

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.