invalid conversion from ‘void*’ to

Gast #6910964
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
}
Gast #6911012
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);
Angehängte Dateien:
Gast #6911031
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.
#6911064
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);
Gast #6911069
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.
Gast #6911160
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!
#6912061
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.
Gast #6912078
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.
Gast #6912088
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
}
?
Gast #6912112
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren