Forum: Mikrocontroller und Digitale Elektronik invalid conversion from ‘void*’ to


von epikao (Gast)


Lesenswert?

Hallo

Aus der LVGL Bibliothek habe ich gewisse Meter Beispiele die eine 
Funktion verwenden, bei der mein Compiler immer was auszusetzen hat, 
siehe Fehler und Funktion unten.

Was ist da falsch? Stimmt etwas mit dem "void*" nicht ?

Danke

Error:
1
src\main.cpp:164:45: error: invalid conversion from ‘void*’ to ‘lv_meter_indicator_t*’ [-fpermissive]

Function:
1
static void set_value( void* indic, int32_t v)
2
{
3
   lv_meter_set_indicator_end_value(meter, indic, v);
4
}

von Programmierer (Gast)


Lesenswert?

Wie sind lv_meter_set_indicator_end_value und "meter" definiert?

von Oliver S. (oliverso)


Lesenswert?

C++ mag keine impliziten Casts von und zu void*, wie das in C üblich 
ist. C Code als C++ compiliert halt nicht immer.

Schreib einen expliziten static_cast davor, dann ist auch der 
C++-Compiler zufrieden, bzw. überlässt dir die Verantwortung für die 
möglichen Probleme.

Oliver

: Bearbeitet durch User
von Christian (Gast)


Lesenswert?

Hast Du es mal mit einem cast versucht:

lv_meter_set_indicator_end_value(meter, (lv_meter_indicator_t*)indic, 
v);

von uff basse (Gast)


Lesenswert?

Oliver S. schrieb:
> bzw. überlässt dir die Verantwortung für die
> möglichen Probleme.

Ob dem TO klar ist was in diesem Fall auf ihn zukommt ... (?)
(denn er sieht ja nicht mal was er aktuell falsch macht)

von epikao (Gast)


Angehängte Dateien:

Lesenswert?

Danke aber phuu da fehlen mir wohl einiges an Grundlagen... :-(

für
1
 lv_anim_set_exec_cb(&a, set_value);
 wird scheinbar die oben erwähnte Funktion benötigt. Aber keine Ahnung 
wie man das C++ gerecht umschreiben sollte... unten noch der eigentliche 
"UI" Code:
1
    meter = lv_meter_create(lv_scr_act());
2
    lv_obj_center(meter);
3
    lv_obj_set_size(meter, 200, 200);
4
5
    /*Add a scale first*/
6
    lv_meter_scale_t * scale = lv_meter_add_scale(meter);
7
    lv_meter_set_scale_ticks(meter, scale, 41, 2, 10, lv_palette_main(LV_PALETTE_GREY));
8
    lv_meter_set_scale_major_ticks(meter, scale, 8, 4, 15, lv_color_black(), 10);
9
10
    lv_meter_indicator_t * indic;
11
12
    /*Add a blue arc to the start*/
13
    indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_BLUE), 0);
14
    lv_meter_set_indicator_start_value(meter, indic, 0);
15
    lv_meter_set_indicator_end_value(meter, indic, 20);
16
17
    /*Make the tick lines blue at the start of the scale*/
18
    indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_BLUE), false, 0);
19
    lv_meter_set_indicator_start_value(meter, indic, 0);
20
    lv_meter_set_indicator_end_value(meter, indic, 20);
21
22
    /*Add a red arc to the end*/
23
    indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_RED), 0);
24
    lv_meter_set_indicator_start_value(meter, indic, 80);
25
    lv_meter_set_indicator_end_value(meter, indic, 100);
26
27
    /*Make the tick lines red at the end of the scale*/
28
    indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_RED), lv_palette_main(LV_PALETTE_RED), false, 0);
29
    lv_meter_set_indicator_start_value(meter, indic, 80);
30
    lv_meter_set_indicator_end_value(meter, indic, 100);
31
32
    /*Add a needle line indicator*/
33
    indic = lv_meter_add_needle_line(meter, scale, 4, lv_palette_main(LV_PALETTE_GREY), -10);
34
35
    /*Create an animation to set the value*/
36
    lv_anim_t a;
37
    lv_anim_init(&a);
38
    lv_anim_set_exec_cb(&a, set_value);
39
    lv_anim_set_var(&a, indic);
40
    lv_anim_set_values(&a, 0, 100);
41
    lv_anim_set_time(&a, 2000);
42
    lv_anim_set_repeat_delay(&a, 100);
43
    lv_anim_set_playback_time(&a, 500);
44
    lv_anim_set_playback_delay(&a, 100);
45
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
46
    lv_anim_start(&a);

von epikao (Gast)


Lesenswert?

Christian schrieb:
> lv_meter_set_indicator_end_value(meter, (lv_meter_indicator_t*)indic,
> v);

Danke, das funktioniert.

uff basse schrieb:
> Ob dem TO klar ist was in diesem Fall auf ihn zukommt ... (?)
> (denn er sieht ja nicht mal was er aktuell falsch macht)

Nein ist mir nicht klar, vielleicht ein paar Stichworte?

von uff basse (Gast)


Lesenswert?

epikao schrieb:
> vielleicht ein paar Stichworte?

Ich meinte das Casten mit oder auf einem Void Pointer.

von Programmierer (Gast)


Lesenswert?

C++-typischer und etwas sauberer wäre:
1
static void set_value( void* indic, int32_t v)
2
{
3
 
4
 lv_meter_set_indicator_end_value(meter, static_cast<lv_meter_indicator_t*> (indic), v);
5
}

Das Problem ist halt, dass es sich um ein C-API handelt. Die können 
prinzipbedingt nicht sehr typsicher sein und erfordern dann solche 
"gefährlichen" casts. Vermutlich muss es genau so sein, aber man müsste 
sich das API genau ansehen um es zu prüfen. Ein gut durchdachtes C++-API 
würde solche Dinge unnötig machen, aber den Luxus haben wir hier wohl 
nicht.

von Dergute W. (derguteweka)


Lesenswert?

Moin,
Wenn du nicht im code selber 'rumcasten willst: haste mal gemacht, was 
der Compiler bei der Fehlermeldung schon vorgeschlagen hat:
Mal mit "-fpermissive" als Option zu compilieren?

Gruss
WK

von Axel S. (a-za-z0-9)


Lesenswert?

Programmierer schrieb:

> Das Problem ist halt, dass es sich um ein C-API handelt.

Die gezeigte Funktion könnte sehr wohl Teil eines C++ API sein. Auch da 
gibt es freestanding Funktionen (im Gegensatz zu Methoden).

Der Fehler ist die Verwendung des void*. Es müßte aber ein Pointer auf 
ein Objekt vom Typ lv_meter_indicator_t sein. Oder - wenn es 
universeller sein soll - auf ein Objekt einer Basisklasse (gerne rein 
virtuell) die die erforderlichen Methoden definiert. Offensichtlich ist 
beim API ein wenig (haha) geschlampt worden.

@TE: der cast maskiert dein Problem nur. Der verhindert nicht, daß 
jemand die Funktion so aufruft:
1
int x= 42;
2
set_value(&x, 0815);

von Programmierer (Gast)


Lesenswert?

Axel S. schrieb:
> Die gezeigte Funktion könnte sehr wohl Teil eines C++ API sein. Auch da
> gibt es freestanding Funktionen (im Gegensatz zu Methoden).
>
> Der Fehler ist die Verwendung des void*.

Es ist ein Callback, und mangels templates muss man in C Callbacks halt 
mit "void*" verwenden für user_data-Parameter. In C++ könnte man den 
Callback als template-"Funktional" übergeben und halt direkt den 
richtigen Typ reinsetzen, oder ein Lambda mit Closure und/oder 
std::function, oder ganz klassisch Strategy Pattern. Klar KANN man das 
in C++ genau so machen wie in C, aber dann verschenkt man Möglichkeiten 
und Sicherheit.

von EAF (Gast)


Lesenswert?

Programmierer schrieb:
> Klar KANN man das
> in C++ genau so machen wie in C, aber dann verschenkt man Möglichkeiten
> und Sicherheit.

Der Weg in die Hölle ist mit expliziten Konvertierungen gepflastert.

von Programmierer (Gast)


Lesenswert?

EAF schrieb:
> Der Weg in die Hölle ist mit expliziten Konvertierungen gepflastert.

So ist es, und deswegen schreibt man sie auch aus (static_cast, 
reinterpret_cast, dynamic_cast, const_cast) statt die Klammer-Syntax von 
C zu verwenden, damit sie hervorstechen und man sofort sieht, wo der 
Fehler sitzt!

von Rolf M. (rmagnus)


Lesenswert?

Programmierer schrieb:
> EAF schrieb:
>> Der Weg in die Hölle ist mit expliziten Konvertierungen gepflastert.
>
> So ist es, und deswegen schreibt man sie auch aus (static_cast,
> reinterpret_cast, dynamic_cast, const_cast) statt die Klammer-Syntax von
> C zu verwenden, damit sie hervorstechen und man sofort sieht, wo der
> Fehler sitzt!

Nicht nur deshalb, sondern auch, weil sie spezifischer sind und nicht 
einfach mit der Holzhammer-Methode versuchen, alles zu tun, was 
irgendwie geht, um vom Quell- zum Zieltyp zu kommen.

von EAF (Gast)


Lesenswert?

Das eigentliche Problem ist hier, dass wir es mit void Zeigern zu tun 
haben.
Was wohl der C API geschuldet ist. Die genaue Cast Sorte spielt da 
meines Erachtens nach nur eine untergeordnete Rolle. Es ist der Zwang 
zum Cast, welcher (mir) hier deplatziert erscheint.
Offensichtlich ein notwendiger Kompromiss, wenn man die Library(?) 
unverändert weiter verwenden will.

In der C++ Welt sind void* ehr verpönt. Von allen Zeigern, sind die 
void* die kritischsten. Denn sind sie doch das recht genaue Gegenteil 
von "Typesicher", und "Typesicherheit" steht recht weit oben auf der C++ 
Featureliste.

Man könnte evt. einen C++ OOP Wrapper drum rum stricken. Wird aber wohl 
eher nicht schön, wenn die Basis nicht von vornherein auf OOP 
ausgerichtet ist.

von EAF (Gast)


Lesenswert?

Programmierer schrieb:
> C++-typischer und etwas sauberer wäre:
> static void set_value( void* indic, int32_t v)
> {
>
>  lv_meter_set_indicator_end_value(meter,
> static_cast<lv_meter_indicator_t*> (indic), v);
> }


Nicht eher so:
1
static void set_value(lv_meter_indicator_t *indic, int32_t v)
2
{
3
 
4
  lv_meter_set_indicator_end_value(meter, indic, v);
5
}
?

von Programmierer (Gast)


Lesenswert?

EAF schrieb:
> Nicht eher so:

Nein, denn dann würde hier ein Fehler auftauchen:

epikao schrieb:
> lv_anim_set_exec_cb(&a, set_value);

Und den Funktionspointer will/darf man nicht casten!

von Johannes S. (Gast)


Lesenswert?

lvgl ist sehr sauber strukturiert in C gebaut, das meter widget und 
andere haben da schon typisierte Funktionen.

Programmierer schrieb:
>> lv_anim_set_exec_cb(&a, set_value);

genau das ist der Punkt, das ist eine generische Animationsfunktion und 
die kann dann nur den void* als Adresse haben. Die ist üblicherweise nur 
für
Demofunktionen, wenn man da casten muss, dann würde mich das nicht 
stören. Gut ist ja das C++ erstmal meckert und den cast erzwingt.

lvgl wird auch plain C bleiben, es gibt generierte Wrapper für 
Micropython und ein C++ Interface würde auch so erstellt, das wurde in 
lvgl issues schon mehrfach diskutiert. lvgl zu modifizieren ist keine 
gute Idee, damit hängt man sich von der (stürmischen) Weiterentwicklung 
ab, da ist ein kleiner cast die kleinere Kröte.
Die Beispiele meckern nicht weil da alles C ist, man kann die anim 
Funktion auch aus dem main.cpp rausnehmen und in einer C unit lassen.

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.