Forum: PC-Programmierung warning: cast of function type call


von Groma (Gast)


Lesenswert?

Hallo,

ich habe eine Frage zu einer Warnung.
Folgender Code in C generiert die unten stehende Warnung
Return type der Funktion ist float
1
sprintf(answer_buf,"%i",(int)RoomSensor_getTemperature());
warning: cast from function call of type 'float' to non-matching type 
'int'

Warum ist hier dier cast nicht erlaubt. Wenn ich diesen weglasse kommt 
natürlich format '%i' expects type 'int', but argument 3 has type 
'double'.

Der code funktioniert zwar, aber mich würde interessiern warum die 
Warnung und wie geht es richtig.

Vielen Dank schon mal

von Fritz G. (fritzg)


Lesenswert?

Kann ich nicht nachvollziehen. Weder mit clang 8.0.0, gcc 6.3.1 oder mit 
Brain 1.0.

von nicht"Gast" (Gast)


Lesenswert?

Der Compiler meckert einfach an, dass er double nicht in int 
convertieren mag.

Es gehen dabei ja informationen verloren.

Gibt statt %i einfach %f an.

von Fritz G. (fritzg)


Lesenswert?

Dann würde die Meldung lauten: "I have no Lust zum konvertieren" ;)

Welche Warnungen hast du eingeschaltet? Bei -Wall geht es bei mir.

Edit: Ich habe es gefunden: -Wbad-function-cast

Nimm das raus oder mach "%.0f" als Format.

: Bearbeitet durch User
von Groma (Gast)


Lesenswert?

Also einfach %f nehme ich nicht, sonst würde ich ja nicht %i nehmen.

Fritz G. schrieb:
> Edit: Ich habe es gefunden: -Wbad-function-cast

Richtig habe ich hinzugefügt.

Fritz G. schrieb:
> Nimm das raus oder mach "%.0f" als Format.

Ja ok das geht, aber ist das auch schon die einzige Lösung oder gibt es 
da etwas "eleganteres"? Bzw. warum kann beim Funktionsaufruf nicht 
direkt einen cast für den Rückgabewert machen?

Ich möchte ja etwas lernen und nicht nur einen workaround.

Sg

von Fritz G. (fritzg)


Lesenswert?

Man kann float auf int casten, verliert aber Genauigkeit. Ich denke, 
jeder der sowas "Böses" macht, weiss das auch. Also nimm den Schalter 
für die Warnung raus, ich finde die wirklich übertrieben.

von Groma (Gast)


Lesenswert?

Fritz G. schrieb:
> Man kann float auf int casten, verliert aber Genauigkeit. Ich denke,
> jeder der sowas "Böses" macht, weiss das auch. Also nimm den Schalter
> für die Warnung raus, ich finde die wirklich übertrieben.


Ok, somit zeigt mir die Warnung auch nur an, dass ich hier die 
genauigkeit verliere und sonst nichts?

Wenn dem so ist, dann werfe ich die Warnung gleich wieder raus.

von Fritz G. (fritzg)


Lesenswert?

-Wall reicht aus.

von Groma (Gast)


Lesenswert?

Super vielen Dank für Eure hilfe.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Weiß jemand, warum es die Option -Wbad-function-cast beim GCC (und auch
Clang) überhaupt gibt? Mir erscheint sie aus den folgenden Gründen
irgendwie sinnlos:

- Die Warnung bezieht sich nur auf Casts von Funktionsrückgabewerten.
  Für andere Ausdrücke kann ich keine entsprechende Option finden. Was
  ist an Funktionswerten so Besonderes, dass man speziell dafür eine
  Warnung braucht?

- Wenn der Programmierer einen Cast hinschreibt, zeigt das, dass er sich
  bewusst ist, dass sich der Wert durch die Konvertierung ändern kann.
  Gefährlicher sind implizite Konvertierungen (also ohne Cast), die oft
  mit Überraschungen verbunden sind. Dort gibt aber -Wbad-function-cast
  keine Warnung aus¹.

- Diese Option gibt es beim GCC nur für C und Objective C, aber nicht
  für C++. Clang meckert die Option für C++ zwar nicht an, ignoriert sie
  aber einfach. Was ist an Funktionsaufrufen in C++ anders, dass man
  hier eine Unterscheidung braucht?

Mir fällt, ehrlich gesagt, kein Grund ein, warum man diese Warnoption
verwenden sollte.

———————————
¹) Dafür gibt es eine eigene (sinnvollere) Option, nämlich -Wconversion,
   die auch nicht nur für Funktionsaufrufe, sondern für beliebige
   Ausrücke gilt. Diese Option gibt keine Warnung aus, wenn ein Wert
   gecastet wird. Sie verhält sich also gerade andersherum als
   -W-bad-function-cast.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Urgestein von 1994. Die Warnung soll wohl hilfreich sein, wenn der Autor 
zu faul[tm] war um Prototypen zu schreiben:
1
$ svn diff -r7560:7564 .
2
3
Index: toplev.c
4
===================================================================
5
--- toplev.c    (revision 7560)
6
+++ toplev.c    (revision 7564)
7
@@ -589,6 +589,8 @@ char *lang_options[] =
8
   "-fno-short-enums",
9
 
10
   "-Wall",
11
+  "-Wbad-function-cast",
12
+  "-Wno-bad-function-cast",
13
   "-Wcast-qual",
14
   "-Wno-cast-qual",
15
   "-Wchar-subscripts",
16
Index: c-typeck.c
17
===================================================================
18
--- c-typeck.c  (revision 7560)
19
+++ c-typeck.c  (revision 7564)
20
@@ -3606,6 +3606,11 @@ build_c_cast (type, expr)
21
          && !TREE_CONSTANT (value))
22
        warning ("cast from pointer to integer of different size");
23
 
24
+      if (warn_bad_function_cast
25
+         && TREE_CODE (value) == CALL_EXPR
26
+         && TREE_CODE (type) != TREE_CODE (otype))
27
+       warning ("cast does not match function type");
28
+
29
       if (TREE_CODE (type) == POINTER_TYPE
30
          && TREE_CODE (otype) == INTEGER_TYPE
31
          && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
32
Index: c-tree.h
33
===================================================================
34
--- c-tree.h    (revision 7560)
35
+++ c-tree.h    (revision 7564)
36
@@ -429,6 +429,12 @@ extern int warn_nested_externs;
37
 
38
 extern int warn_cast_qual;
39
 
40
+/* Nonzero means warn when casting a function call to a type that does
41
+   not match the return type (e.g. (float)sqrt() or (anything*)malloc()
42
+   when there is no previous declaration of sqrt or malloc.  */
43
+
44
+extern int warn_bad_function_cast;
45
+
46
 /* Warn about traditional constructs whose meanings changed in ANSI C.  */
47
 
48
 extern int warn_traditional;
49
Index: c-decl.c
50
===================================================================
51
--- c-decl.c    (revision 7560)
52
+++ c-decl.c    (revision 7564)
53
@@ -466,6 +466,12 @@ int warn_write_strings;
54
 
55
 int warn_cast_qual;
56
 
57
+/* Nonzero means warn when casting a function call to a type that does
58
+   not match the return type (e.g. (float)sqrt() or (anything*)malloc()
59
+   when there is no previous declaration of sqrt or malloc.  */
60
+
61
+int warn_bad_function_cast;
62
+
63
 /* Warn about traditional constructs whose meanings changed in ANSI C.  */
64
 
65
 int warn_traditional;
66
@@ -621,6 +627,10 @@ c_decode_option (p)
67
     warn_cast_qual = 1;
68
   else if (!strcmp (p, "-Wno-cast-qual"))
69
     warn_cast_qual = 0;
70
+  else if (!strcmp (p, "-Wbad-function-cast"))
71
+    warn_bad_function_cast = 1;
72
+  else if (!strcmp (p, "-Wno-bad-function-cast"))
73
+    warn_bad_function_cast = 0;
74
   else if (!strcmp (p, "-Wpointer-arith"))
75
     warn_pointer_arith = 1;
76
   else if (!strcmp (p, "-Wno-pointer-arith"))

Review dazu hab ich keines gefunden; die ML-Archive reichen nur bis ca. 
1998 zurück.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
> Urgestein von 1994. Die Warnung soll wohl hilfreich sein, wenn der Autor
> zu faul[tm] war um Prototypen zu schreiben:

Danke dafür, dass du die Änderung extra herausgesucht hast. Das bringt
schon etwas Licht ins Dunkel und erklärt auch die Unterscheidung
zwischen C und C++, da es in C++ keine impliziten Funktionsdeklarationen
gibt).

Was ich aber trotzdem noch nicht ganz verstehe:

> +/* Nonzero means warn when casting a function call to a type that does
> +   not match the return type (e.g. (float)sqrt() or (anything*)malloc()
> +   when there is no previous declaration of sqrt or malloc.  */
> +
> +extern int warn_bad_function_cast;

Ich verstehe das so, dass die Warnung nur kommen soll, wenn die
aufgerufene Funktion nicht vorher schon deklariert wurde. Aber auch eine
nichtdeklarierte Funktion hat ja einen eindeutigen Ergebnistyp, nämlich
int. Was ist schlecht daran, dieses int in irgendeinen anderen Typ zu
casten? Ganz abgesehen davon kommt die Warnung auch dann, wenn die
Funktion vorher ordnungsgemäß deklariert (egal, ob im K&R- oder im
ANSI-Stil) wurde.

von Dussel (Gast)


Lesenswert?

Yalu X. schrieb:
> - Die Warnung bezieht sich nur auf Casts von Funktionsrückgabewerten.
>   Für andere Ausdrücke kann ich keine entsprechende Option finden. Was
>   ist an Funktionswerten so Besonderes, dass man speziell dafür eine
>   Warnung braucht?
Variablen werden fast immer in der Funktion oder als Übergabeparameter 
deklariert. Damit ist in nächster Nähe ersichtlich, welchen Typ die 
Variable hat.
Funktionen werden oft in Headerdateien deklariert, so dass man nicht 
unbedingt auf die Schnelle sieht, welchen Rückgabetyp sie haben. Deshalb 
gibt es die Möglichkeit, sich warnen zu lassen.
Das wäre meine Überlegung. Wenn das der Grund ist, müsste es auch eine 
Warnung bei/für globale Variablen geben.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Was ich aber trotzdem noch nicht ganz verstehe:
>
>> +/* Nonzero means warn when casting a function call to a type that does
>> +   not match the return type (e.g. (float)sqrt() or (anything*)malloc()
>> +   when there is no previous declaration of sqrt or malloc.  */
>> +
>> +extern int warn_bad_function_cast;
>
> Ich verstehe das so, dass die Warnung nur kommen soll, wenn die
> aufgerufene Funktion nicht vorher schon deklariert wurde.
> Aber auch eine nichtdeklarierte Funktion hat ja einen
> eindeutigen Ergebnistyp, nämlich int. Was ist schlecht daran,
> dieses int in irgendeinen anderen Typ zu casten? Ganz abgesehen
> davon kommt die Warnung auch dann, wenn die
> Funktion vorher ordnungsgemäß deklariert (egal, ob im K&R- oder im
> ANSI-Stil) wurde.

So richtig verstehen tu ich das auch nicht, vielleicht hat die Warnung 
damals vor 22 Jahren noch etwas anders funktioniert weil der Kontext 
damals ein anderer war.  Hat sich im GCC ja einiges geändert seitdem.

Außerdem ist die Warnung standardmäßig aus, und wer sie aktiviert hat, 
wird sie (heute) wenig hilfreich finden wie der TO ja auch.

Wesentlich sinnvoller sind da m.E. -Wstrict-prototypes und 
-Wmissing-prototyes, insbesondere für Targets wie AVR wo man ohne 
Prototypen keinen korrekten Code bekommt.  Ob es vor 22 Jahren schon 
solche Targets gab?  Keine Ahnung, jedenfalls waren es damals bestimmt 
weniger als heute.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ok, dann lege ich die Option einfach zum Antiquariat. Ich kann ich das
ganz gut verschmerzen, da ich bis heute morgen nicht einmal wusste, dass
es sie überhaupt gibt :)

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.