Forum: PC-Programmierung C - warning: incompatible integer to pointer conversion assigning to 'void *' from 'int' [-Wint-conv


von Dennis (Gast)


Lesenswert?

Hey, ich experimentiere gerade ein wenig mit Functions, Pointern und 
Void-Pointern.

Das unten aufgeführte Script läuft und gibt das richtige Ergebnis, 
jedoch bekomme ich auf die Zeile
1
b=*(int*)a;
 folgende Warnung: "warning: incompatible integer to pointer conversion 
assigning to 'void *' from 'int'"

Ich versuche verzweifelt den Hintergrund zu verstehen, komme aber leider 
nicht dahinter :/

1
#include <stdio.h>
2
3
void test (int *a);
4
void test2 (int d);
5
void *stage (const void*);
6
void *stage2 (const void*);
7
8
int main() {
9
10
    int f=0;
11
12
    //test(&e);
13
    //test2(e);
14
15
    if (f==0) {
16
        stage(&f);
17
        printf("\n%d",f);
18
    }
19
20
    if (f==1) {
21
        stage(&f);
22
        printf("\n%d",f);
23
    }
24
25
    if (f==2) {
26
        f=*(long*)stage2(&f);
27
        printf("\n%d",f);
28
    }
29
30
    if (f==3) {
31
        f=*(long*)stage2(&f);
32
        printf("\n%d",f);
33
    }
34
    return 0;
35
}
36
37
void test(int *a) { 
38
    int b=3;
39
    int c=2;
40
    *a=b+c; 
41
}
42
43
void test2(int d) {
44
    d++;
45
    //printf("%d",d);
46
}
47
48
void *stage (const void*num) {
49
    long nr;
50
    nr=(*(int*)num)++;
51
    return (void*)nr;
52
}
53
54
void *stage2(const void*a) {
55
    static void *b;
56
    b=*(int*)a;
57
58
    if (b==(int*)2)
59
        b+=1;
60
    else if (b==(int*)3)
61
        b+=6;
62
63
    return &b;
64
}

von Walter K. (vril1959)


Lesenswert?

Was ist an „ " incompatible integer to pointer conversion assigning to 
'void *' from 'int'" unverständlich?

Beitrag #5746535 wurde von einem Moderator gelöscht.
von Dirk B. (dirkb2)


Lesenswert?

Rechts vom = steht ein int (der gesamte Ausdruck)

Ein Pointer ist keine Ganzzahl. Auch wenn es manchmal so aussieht.
Verlasse dich bei diesen Experimenten auf Nichts.
Sie haben auch keine nachvollziehbare Aussage.

Es kann mit einem anderen Compiler/Version/Optimierungsstufe/System 
anders aussehen

von Dr. Sommer (Gast)


Lesenswert?

In C schreibt man keine Scripte sondern Programme. C ist schließlich 
keine Scriptsprache. Dein Programm enthält mehrere Fehler und 
funktioniert daher nicht; es hat nur zufällig den Anschein zu 
funktionieren. Durch Änderung der Umgebung (Compiler-Version, -Optionen, 
Betriebssystem, Prozessor) kann das schon ganz anders aussehen.

Dennis schrieb:
> return (void*)nr;

Irgendeinen long-Wert nach void* casten ist fehlerhaft. Es können Daten 
verloren gehen (der long ist ggf. nicht wiederherstellbar) und beim 
Dereferenzieren des Pointers kann beliebiger Unfug passieren. Es 
"funktioniert" nur weil du den Rückgabewert nirgends verwendest.

Dennis schrieb:
> if (b==(int*)2)

Was soll das sein? Einen Integer vom Wert "2" in einen Pointer-Typ zu 
casten ergibt Unsinn. Der Compiler warnt zu recht.

Dennis schrieb:
> return &b;

Hier fehlt ein cast. &b ist vom Typ void**.

Dennis schrieb:
> f=*(long*)stage2(&f);

Hier dereferenzierst du einen Pointer vom Typ "long*" welcher aber auf 
ein *b zeigt und schneidest dann noch ggf. Bits ab (cast nach int). Es 
wird also der ggf. gekürzte Wert in "b" ausgegeben, d.h. die Adresse von 
f.
Würde einer der if-Blöcke ausgeführt, wäre diese Adresse inkrementiert 
und damit ungültig.

So ein Code ist natürlich nicht nur fehlerhaft, sondern auch unlesbar 
und unwartbar. Auf die Nutzung von void*, das Casten zwischen 
verschiedenen Pointer-Typen und insbesondere das Casten zwischen 
Pointern und Integern sollte man so weit wie irgend möglich vermeiden 
(das geht in C++ übrigens besser als in C dank templates). Falls man 
doch zwischen Pointer und Integer casten muss, sollte man das nur mit 
dem Integer-Typ "uintptr_t" machen, auf keinen Fall mit "long" oder 
"int". Auf AMD64 z.B. ist ein Zeiger 64bit-lang, "long" und "int" aber 
meist (je nach Compiler) nur 32bit. Somit gehen 32bits verloren. 
Umgekehrt ist auf x86 ein Pointer nur 32bit groß, ein "long" könnte je 
nach Compiler 64bit sein wodurch wieder Daten verloren gehen wenn man 
den "long" auf den Zeiger umwandelt. uintptr_t ist immer richtig groß. 
Irgendwelche Zahlen (2, 3) nach Pointer casten ist zwar möglich, aber 
hässlich - diesen Zeiger darf man nicht dereferenzieren, sondern nur 
wieder zurück auf den Integer casten.

Stelle deinen Compiler auf einen strikten Sprachstandard (ohne 
Erweiterungen) und aktiviere alle Warnungen. So lernt man am Besten. 
Beim GCC geht das z.B. mit den Optionen "-std=c11 -Wall -Wextra 
-Wconversion -pedantic -Werror". Code der damit anstandslos übersetzt 
wird hat eine deutlich höhere Wahrscheinlichkeit, dass er korrekt ist.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Sehen wir uns doch die nähere Umgebung mal an:
1
void *stage2(const void*a) {
2
    static void *b;
3
    b=*(int*)a;

Hier wird der void-Pointer a also zu einem int-Pointer gecastet:
1
    (int *) a

dieser int-Pointer dann dereferenziert
1
   * ((int *) a)

und das Ergebis --ein int-- einem void-Pointer zugewiesen:
1
   b = * ((int *) a)

(Die zusätzlichen Klammern dienen dem Verständnis, worauf sich der 
jeweilige Operator bezieht)


Und damit sollte die Warnung des Compilers verständlich sein:

"Zuweisung eines ints zu einem Pointer"

Man könnte jetzt noch einen zusätzlichen Typecast einführen
1
   b = (void *) (* ((int *) a))

dann wäre die Warnung weg.

von c-hater (Gast)


Lesenswert?

Rufus Τ. F. schrieb:

> Man könnte jetzt noch einen zusätzlichen Typecast einführen
>
>
1
>    b = (void *) (* ((int *) a))
2
>
>
> dann wäre die Warnung weg.

Und der ganze syntaktische Aufwand nur, um eine aus Sicht der Maschine 
völlig legale Operation auch für den Compiler zu legalisieren...

Wenn man das dann noch unter besonderer Berücksichtigung des 
Sachverhalts betrachtet, dass bei Maschinen, wo diese Operation nicht 
legal ist, das Geschwalle zwar den Compiler ruhig stellt, aber letztlich 
trotzdem nix funktionieren wird, sollten dann doch erste Zweifel am 
Nutzen dieses ganzen Geschwalles aufkommen...

Aber natürlich: wenn C die Bibel ist, dann ist es von Gott gegeben, dass 
C alles löst und überhaupt...

42

von (prx) A. K. (prx)


Lesenswert?

Wieder auf Streit aus?

von leo (Gast)


Lesenswert?

c-hater schrieb:
> Aber natürlich: wenn C die Bibel ist, dann ist es von Gott gegeben, dass
> C alles löst und überhaupt...

Du schliesst von extrem schlechten, unleserlichen und sinnfreien Code 
zum Experimentieren auf die Sprache um deinen Mist abzuladen.

leo

von Dennis (Gast)


Lesenswert?

Vielen Dank für die raschen und ausführlichen Antworten.

Das hilft mir schon etwas beim Verständnis :)

von Besser gar keinen Cast benutzen (Gast)


Lesenswert?

Wir sollten den Anfängern besser den Rat geben: Datenstrukturen so 
anlegen, das keine Casts erforderlich sind. Casts nur in einigen 
Sonderfällen wie malloc() oder memcpy() nutzen. Vor allem, niemals von 
Const-Pointer auf Nicht-Const casten. Das gibt immer undurchschaubare 
Probleme.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Irgendwelche Zahlen (2, 3) nach Pointer casten ist zwar möglich, aber
> hässlich - diesen Zeiger darf man nicht dereferenzieren, sondern nur
> wieder zurück auf den Integer casten.

Für memory mapped Register, IO und bestimmte Speicherbereiche ist das 
doch völlig normal. Daß man das in defines kapselt, ist ja bloß 
Textersetzung.

von Dirk B. (dirkb2)


Lesenswert?

Besser gar keinen Cast benutzen schrieb:
> Casts nur in einigen Sonderfällen wie malloc() oder memcpy() nutzen.

In C sind da keine Cast nötig.
In C++ verwendet man sie (zumindest malloc) nicht.

von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Wieder auf Streit aus?

Dirk B. schrieb:
> Besser gar keinen Cast benutzen schrieb:
>> Casts nur in einigen Sonderfällen wie malloc() oder memcpy() nutzen.
>
> In C sind da keine Cast nötig.
> In C++ verwendet man sie (zumindest malloc) nicht.

Und bei memcpy ist auch in C++ kein Cast nötig.

von Mark B. (markbrandis)


Lesenswert?

Dirk B. schrieb:
> Besser gar keinen Cast benutzen schrieb:
>> Casts nur in einigen Sonderfällen wie malloc() oder memcpy() nutzen.
>
> In C sind da keine Cast nötig.
> In C++ verwendet man sie (zumindest malloc) nicht.

Bitte was?

malloc() liefert doch einen Zeiger vom Typ void* zurück. Seit wann kann 
man sowas verwenden ohne zu casten?

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Mark B. schrieb:
> malloc() liefer doch einen Zeiger vom Typ void* zurück. Seit wann kann
> man sowas verwenden ohne zu casten?

C erlaubt die implizite Konvertierung von void* auf andere Zeiger-Typen, 
damit die armen C-Programmierer nicht ständig casten müssen (ala "int* f 
= (int*) malloc (sizeof(int));"). In C++ schreibt man halt einfach "new 
int".

von Mark B. (markbrandis)


Lesenswert?

Dr. Sommer schrieb:
> C erlaubt die implizite Konvertierung von void* auf andere Zeiger-Typen,
> damit die armen C-Programmierer nicht ständig casten müssen (ala "int* f
> = (int*) malloc (sizeof(int));"). In C++ schreibt man halt einfach "new
> int".

Oh, okay. Ich habe bei malloc() immer gecastet... hat immer funktioniert 
;-)

von Dr. Sommer (Gast)


Lesenswert?

Mark B. schrieb:
> Oh, okay. Ich habe bei malloc() immer gecastet... hat immer funktioniert
> ;-)

Ist auch sinnvoll, damit der Code auch unter C++ funktioniert.

von Dirk B. (dirkb2)


Lesenswert?

Dr. Sommer schrieb:
> Mark B. schrieb:
>> Oh, okay. Ich habe bei malloc() immer gecastet... hat immer funktioniert
>> ;-)
>
> Ist auch sinnvoll, damit der Code auch unter C++ funktioniert.

C Programme sollte man mit einem C-Compiler übersetzen.

Den bieten die allermeisten C++-Compiler auch an.

von Carl D. (jcw2)


Lesenswert?

Dirk B. schrieb:
> Dr. Sommer schrieb:
>> Mark B. schrieb:
>>> Oh, okay. Ich habe bei malloc() immer gecastet... hat immer funktioniert
>>> ;-)
>>
>> Ist auch sinnvoll, damit der Code auch unter C++ funktioniert.
>
> C Programme sollte man mit einem C-Compiler übersetzen.
>
> Den bieten die allermeisten C++-Compiler auch an.

Vielleicht hat man aber ein Stück C-Code, das man in eine C++-Source 
einfügen will. Das hat Dr.Sommer wohl sagen wollen.

von Rolf M. (rmagnus)


Lesenswert?

Mark B. schrieb:
> Dr. Sommer schrieb:
>> C erlaubt die implizite Konvertierung von void* auf andere Zeiger-Typen,
>> damit die armen C-Programmierer nicht ständig casten müssen (ala "int* f
>> = (int*) malloc (sizeof(int));"). In C++ schreibt man halt einfach "new
>> int".
>
> Oh, okay. Ich habe bei malloc() immer gecastet... hat immer funktioniert
> ;-)

Das sollte man in C aber besser nicht tun.

Carl D. schrieb:
>> C Programme sollte man mit einem C-Compiler übersetzen.
>>
>> Den bieten die allermeisten C++-Compiler auch an.
>
> Vielleicht hat man aber ein Stück C-Code, das man in eine C++-Source
> einfügen will. Das hat Dr.Sommer wohl sagen wollen.

Davon würde ich abraten. Wenn man das braucht, steckt man den C-Code in 
eine C-Datei. Die Funktionen lassen sich problemlos auch von C++-Code 
aus aufrufen. Es gibt doch ein paar subtile Unterschiede, durch die ich 
nicht einfach blind darauf vertrauen würde, dass C-Code als C++ noch 
genau gleich funktioniert.

von Mark B. (markbrandis)


Lesenswert?

Rolf M. schrieb:
> Mark B. schrieb:
>> Oh, okay. Ich habe bei malloc() immer gecastet... hat immer funktioniert
>> ;-)
>
> Das sollte man in C aber besser nicht tun.

Warum nicht?

von Rolf M. (rmagnus)


Lesenswert?

Mark B. schrieb:
>> Das sollte man in C aber besser nicht tun.
>
> Warum nicht?

Falls du mal das dazugehörige #include <stdlib.h> vergisst, fehlt eine 
Deklaration für malloc. Standard-Verhalten von C ist dann, int als 
Return-Typ anzunhemen. Das geht spätestens dann schief, wenn du auf 
einem System bist, wo int und Zeiger nicht zufällig die gleiche Größe 
haben.
Ohne Cast kommt dann die Meldung, dass du versuchst, einen int in einen 
Zeiger umzuwandeln. Mit Cast sagst du dem Compiler, dass du das so 
willst und unterdrückst damit die Meldung.

von Mark B. (markbrandis)


Lesenswert?

Rolf M. schrieb:
> Falls du mal das dazugehörige #include <stdlib.h> vergisst, fehlt eine
> Deklaration für malloc. Standard-Verhalten von C ist dann, int als
> Return-Typ anzunhemen. Das geht spätestens dann schief, wenn du auf
> einem System bist, wo int und Zeiger nicht zufällig die gleiche Größe
> haben.
> Ohne Cast kommt dann die Meldung, dass du versuchst, einen int in einen
> Zeiger umzuwandeln. Mit Cast sagst du dem Compiler, dass du das so
> willst und unterdrückst damit die Meldung.

Na ja, den Fall halte ich nun nicht gerade für sehr wahrscheinlich.

Edit: Außerdem erhalte ich mit -Wall sowieso eine Warnung:
1
warning: implicit declaration of function 'malloc' [-Wimplicit-function-declaration]

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Ja, die Compiler geben da heute deutlich bessere Warnungen aus als 
früher, daher mag das nicht mehr so von Bedeutung sein.
Ich würde einen nicht nötigen Cast aber abgesehen davon sowieso lieber 
weglassen.

von vn nn (Gast)


Lesenswert?

c-hater schrieb:
> Und der ganze syntaktische Aufwand nur, um eine aus Sicht der Maschine
> völlig legale Operation auch für den Compiler zu legalisieren...

Nö der ganze syntaktische Aufwand ist eigentlich völlig unnötig, aber 
der TS will halt herumspielen.
Aber du hast halt keine Ahnung von C, deswegen glaubst du dass das nötig 
wäre.

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.