Forum: Compiler & IDEs Wahrheit von Zeigerarithmetik


von Gast (Gast)


Lesenswert?

Wenn auf einen Zeiger addiert wird, was kommt dabei heraus, wenn das 
Ergebnis kein gültiger Zeiger mehr ist?
Anders gefragt, wie bekommt man heraus, ob es sich bei einem berechneten 
Zeiger (auf eine Liste) um einen gültigen handelt?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Gast schrieb:

> Wenn auf einen Zeiger addiert wird, was kommt dabei heraus, wenn das
> Ergebnis kein gültiger Zeiger mehr ist?

Je nach System und Ziel des Zeigers z.B. einen bus error oder einen 
segmentation fault oder nix.

> Anders gefragt, wie bekommt man heraus, ob es sich bei einem berechneten
> Zeiger (auf eine Liste) um einen gültigen handelt?

Gültige Zeiger in einer eigenen Liste führen und Rechnen mit Zeigern 
unterlassen.

von Gast (Gast)


Lesenswert?

Ok, dann habe ich das wohl mit einem Zeiger auf einen String 
verwechselt, wo eine True/False Prüfung das gewünschte bewirkt. Danke.

von Karl H. (kbuchegg)


Lesenswert?

Stefan B. schrieb:
> Gast schrieb:
>
>> Wenn auf einen Zeiger addiert wird, was kommt dabei heraus, wenn das
>> Ergebnis kein gültiger Zeiger mehr ist?
>
> Je nach System und Ziel des Zeigers z.B. einen bus error oder einen
> segmentation fault oder nix.

Nicht das ich Stefan da jetzt ins Wort fallen möchte.
Aber mit nix meint er:
  Irgendeine Zahl, so wie bei jeder anderen Zeigerarithmetik auch. Und
  weiters: nix spezielles passiert.
Und er meint damit nicht:
  Ein NULL-Pointer (also ein Pointer mit dem Wert 0)

von Karl H. (kbuchegg)


Lesenswert?

Gast schrieb:
> Ok, dann habe ich das wohl mit einem Zeiger auf einen String
> verwechselt, wo eine True/False Prüfung das gewünschte bewirkt.

Ganz sicher nicht. Das hast du noch einmal verwechselt.

Wenn alles was man hat der Zeiger ist, dann kannst du gründsätzlich 
durch Inspektion des Wertes nicht feststellen, ob dieser gültig ist 
(also auf gültige Daten zeigt) oder nicht.

Daher ist in C bei so etwas

    if( ptr )
      free( ptr );

bzw. in C++

    if( ptr )
      delete ptr;

die Abfrage des Pointer-Wertes eine sinnlose Aktion (in 99% aller Fälle)

Bau dein Programm so auf, dass du dir diese Frage gar ncht stellen musst 
und du hast mehr Freude an deinem Programm.

von Thomas P. (tpircher) Benutzerseite


Lesenswert?

Ob ein Zeiger "gueltig" ist, weiss in der Regel nur der Programmierer. C 
kann und will keine Kontrollmassnahmen zur Gueltigkeit von Zeigern 
ergreifen ("trust the programmer").

Manche Prozessoren koennen erkennen, ob ein Speicherzugriff auf Bereiche 
erfolgt, die nicht zum laufenden Programm gehoeren. Meist wird dann ein 
Interrupt erzeugt, und das Betriebssystem kann den laufenden Prozess 
beenden. Im embedded Bereich ist das aber selten anzutreffen.

> Anders gefragt, wie bekommt man heraus, ob es sich bei einem berechneten
> Zeiger (auf eine Liste) um einen gültigen handelt?

Es ist relativ schwer das run-time herauszufinden. Und was ist der Sinn 
dieser Uebung? Wenn ein unberechtigter Zugriff erfolgt, dann ist das 
Programm schon in einem undefinierten Zustand, in anderen Worten: es ist 
ein Bug vorhanden. Dieser buggy Code kann schon lange zuvor ausgefuehrt 
worden sein. Der ungueltige Speicherzugriff ist nur das Symptom, nicht 
die Ursache deines Problems.

Wenn du den Speicherzugriff debuggen willst, kann es von Vorteil sein, 
das Programm auf Linux zu portieren. Wenn ein Speicherzugriffsfehler 
passiert, wird das Programm beendet und das System erzeugt ein core 
File, wenn erlaubt (ulimit -c unlimited). Ein core File ist ein Abbild 
des Speichers zum Zeitpukt des Fehlers. Dann kannst du den Zustand des 
Programms mit GDB einsehen.

Valgrind ist ein anderes nuetzliches Tool um unerlaubte Speicherzugriffe 
und memory leaks zu ermitteln.

Wenige Tools werden dir helfen, wenn der Zugriff auf einen 'gueltigen' 
Speicherbereich faellt (das heisst, ein Bereich auf den dein Programm 
berechtigt ist zuzugreifen), der aber mit anderen Variablen belegt ist.

von ... (Gast)


Lesenswert?

Das ist sogar in 100% der Fälle eine sinnlose Aktion, da free und delete 
selbst prüfen, ob der Zeiger 0 ist.

von Karl H. (kbuchegg)


Lesenswert?

... schrieb:
> Das ist sogar in 100% der Fälle eine sinnlose Aktion, da free und delete
> selbst prüfen, ob der Zeiger 0 ist.

Würde ich normalerweise auch sagen.
In dem 1% der Fälle, die ich offen lassen möchte, fallen diejenigen, bei 
denen der Pointer in der überwiegenden Mehrheit der Fälle tatsächlich 
NULL ist und man dann tatsächlich den Aufruf einer Funktion einsparen 
kann. Das Potential für eine derartige 'Optimierung' würde ich aber mit 
1% (eher sogar weniger) einschätzen. Aber es mag solche Fälle 
tatsächlich geben.

von Bernhard M. (boregard)


Lesenswert?

... schrieb:
> Das ist sogar in 100% der Fälle eine sinnlose Aktion, da free und delete
> selbst prüfen, ob der Zeiger 0 ist.

...sollten, aber da es nicht alle so machen (nicht alles, wo Posix 
konform draufsteht ist es auch) kann das durchaus Sinn machen.

Ich habe mir das angewöhnt, weil ich damit vor Jahren auf einem alten 
Solaris auf die Nase gefallen bin...

von Karl H. (kbuchegg)


Lesenswert?

Bernhard M. schrieb:
> ... schrieb:
>> Das ist sogar in 100% der Fälle eine sinnlose Aktion, da free und delete
>> selbst prüfen, ob der Zeiger 0 ist.
>
> ...sollten, aber da es nicht alle so machen (nicht alles, wo Posix
> konform draufsteht ist es auch) kann das durchaus Sinn machen.
>
> Ich habe mir das angewöhnt, weil ich damit vor Jahren auf einem alten
> Solaris auf die Nase gefallen bin...

Gut, wenn man den Fall tatsächlich hat, kann man auf die Schnelle 
natürlich wenig dagegen tun. Der Compiler bzw. die Runtime Lib hat immer 
Recht. Aber letztendlich musst du dir bewusst sein, dass du damit einen 
Compiler/Library Bug umgehst, der besser beim Compiler Hersteller gefixt 
wird.

Sinnlos ist die Operation trotzdem. Leider denken viele C++ 
Programmierer, dass sie mit ....

  if( Ptr )
    delete Ptr

a) auf der sicheren Seite sind. Ihnen also nichts passieren kann, denn
   sie haben den Pointer ja auf 'Gültigkeit' geprüft.
b) sie einen wahnsinng cleveren Hack machen um damit Freigaben zu
   beschleunigen.
   Das genaue Gegenteil ist der Fall :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bernhard M. schrieb:

> ...sollten, aber da es nicht alle so machen (nicht alles, wo Posix
> konform draufsteht ist es auch) kann das durchaus Sinn machen.

Das ist nichtmal Posix, das ist C-Standard, und zwar seit Jahren.

von Bernhard M. (boregard)


Lesenswert?

Jörg Wunsch schrieb:
> Bernhard M. schrieb:
>
>> ...sollten, aber da es nicht alle so machen (nicht alles, wo Posix
>> konform draufsteht ist es auch) kann das durchaus Sinn machen.
>
> Das ist nichtmal Posix, das ist C-Standard, und zwar seit Jahren.

Kann sein, daß es das ist; es ist auch richtig, daß es ein Library bug 
ist der vom Hersteller gefixed wird, aber ich kann wegen eines solchen 
Problems keinnen update einer Library (bzw. Patch) beim Kunden 
verlangen...

Ich wollte nur darauf hinweisen, daß allein das Vorhandensein einer 
scheinbar sinnlosen Anweisung nicht heisst, das der Entwickler nichts / 
das falsche gedacht hat...

von der mechatroniker (Gast)


Lesenswert?

Es ist aber eine verbreitete Konvention (und auch der Sinn von NULL im 
Sinne der Spracherfinder), einem Zeiger NULL zuzuweisen, solange er auf 
nichts sinnvolles zeigt. Daher frag ich mich, warum
1
 if(ptr) free(ptr);
falsch ist, solange ich diese Konvention anwende.

Zeiger erst gar nicht prüfen, weil ich micht selbst für einen Idioten 
halte und davon ausgehe, dass eh irgendwo ein Bug drin ist, der dafür 
sorgt, dass ein Nicht-Nullzeiger auftritt, der auf nichts sinnvolles 
zeigt, und ich das ganze eh nicht korrekt hinkrieg, scheint mir eine 
nicht sehr sinnvolle Strategie.

von Oliver (Gast)


Lesenswert?

Von "falsch" hat niemand was gesagt.

Bernhard M. schrieb:
> Das ist sogar in 100% der Fälle eine sinnlose Aktion, da free und delete
> selbst prüfen, ob der Zeiger 0 ist.

Oliver

von Thomas B. (escamoteur)


Lesenswert?

der mechatroniker schrieb:
> Es ist aber eine verbreitete Konvention (und auch der Sinn von NULL im
> Sinne der Spracherfinder), einem Zeiger NULL zuzuweisen, solange er auf
> nichts sinnvolles zeigt. Daher frag ich mich, warum
>
1
 if(ptr) free(ptr);
> falsch ist, solange ich diese Konvention anwende.
>

Für C absolut guter Stil! In c++ ist

delete null

allerdings als korrekt definiert und erzeugt keinen Fehler

Gruß
Tom

von P. S. (Gast)


Lesenswert?

Thomas Burkhart schrieb:

> Für C absolut guter Stil! In c++ ist

man malloc():

free() frees the memory space pointed to by ptr, which must have been 
returned by a previous call to malloc(), calloc() or  realloc(). 
Otherwise, or if free(ptr) has already been called before, undefined 
behaviour occurs.  If ptr is NULL, no operation is performed.

> delete null
>
> allerdings als korrekt definiert und erzeugt keinen Fehler

dito.

Natuerlich immer ausgenommen kaputte Implementationen, wie oben ja schon 
Jemand ausfuehrte.

von Thomas B. (escamoteur)


Lesenswert?

free(null) war früher auf jeden Fall mal nicht definiert. Programmiere 
zu lange C++ um zu sagen ab wann sich das geändert hat.

Gruß
Tom

von Stefan E. (sternst)


Lesenswert?

Thomas Burkhart schrieb:

> Für C absolut guter Stil! In c++ ist
>
> delete null
>
> allerdings als korrekt definiert und erzeugt keinen Fehler

Das gleiche gilt auch für C, also auch dort kein guter Stil, sondern 
schlicht überflüssig.

Schon der steinalte ANSI-C Standard sagt:
1
The free function causes the space pointed to by ptr to be
2
deallocated, that is, made available for further allocation.
3
If ptr is a null pointer, no action occurs.
4
...

von Thomas B. (escamoteur)


Lesenswert?

Ok, dann war meine Erinnerung da falsch.
Gruß
Tom

von P. S. (Gast)


Lesenswert?

Thomas Burkhart schrieb:
> Ok, dann war meine Erinnerung da falsch.

Als Entwickler hat man 2 Moeglichkeiten: Man arbeitet als Entwickler auf 
Basis von veraltetem Know-How, oder man steckt den ganzen Tag die Nase 
in die sich staendig aendernden "Standards" ;-)

von Bernhard M. (boregard)


Lesenswert?

Oliver schrieb:
> Von "falsch" hat niemand was gesagt.
>
> Bernhard M. schrieb:
>> Das ist sogar in 100% der Fälle eine sinnlose Aktion, da free und delete
>> selbst prüfen, ob der Zeiger 0 ist.
>
> Oliver

Da hast Du mich falsch zitiert!!! Das kam nicht von mir.... ;-)

von Oliver (Gast)


Lesenswert?

Oha, stimmt.

Stimmt aber trotzdem ;-)

Oliver

von Karl H. (kbuchegg)


Lesenswert?

der mechatroniker schrieb:
> Daher frag ich mich, warum
>
1
 if(ptr) free(ptr);
> falsch ist, solange ich diese Konvention anwende.
>
> Zeiger erst gar nicht prüfen, weil ich micht selbst für einen Idioten
> halte und davon ausgehe, dass eh irgendwo ein Bug drin ist, der dafür
> sorgt, dass ein Nicht-Nullzeiger auftritt, der auf nichts sinnvolles
> zeigt,

Genau dieser Fehler ist aber der Regelfall eines Fehlers an dieser 
Stelle. Und die Abfrage kann dich nicht davor schützen.

Ein andere 'Konvention', die man auch ab und an sieht:

    some_Type_T * ptr;

    ptr = (some_Type_T*)malloc( .... );

also das zurechtcasten des Ergebnisses von malloc.
Tut das nicht, auch wenn man es des Öfteren sieht. Ihr könnt euch damit 
einen bösen Fehler verstecken!

(*) wobei man sagen muss, dass es einen Fall gibt. Nämlich den, dass 
derselbe Code unverändert durch den C++ Compiler soll. Dann braucht man 
den Cast. Allerdings wäre es besser in so einem Fall den Code so 
umzuarbeiten, dass er new benutzt. Aber bei einem Einsatz eines C 
Compilers ist dieser Cast unnötig und wie die meisten unnötigen Casts 
eine potentielle Fehlerquelle.

von der mechatroniker (Gast)


Lesenswert?

> Genau dieser Fehler ist aber der Regelfall eines Fehlers an dieser
> Stelle. Und die Abfrage kann dich nicht davor schützen.

Was mich davor aber schützt, ist an den kritischen Stellen, an denen der 
Zeiger zugewiesen wird, korrekten Code zu schreiben. Ich könnte 
natürlich eine zusätzliche Variable einführen, die mir sagt, ob ein 
bestimmter Pointer gerade verwendet wird oder nicht. Wenn ich die dann 
aber nicht korrekt mitführe, dann schützt mich die Abfrage genausowenig. 
Und wenn ich sie korrekt mitführe, dann hab ich eine Variable mehr, was 
die Sache nicht übersichtlicher macht.

von Karl H. (kbuchegg)


Lesenswert?

der mechatroniker schrieb:
>> Genau dieser Fehler ist aber der Regelfall eines Fehlers an dieser
>> Stelle. Und die Abfrage kann dich nicht davor schützen.
>
> Was mich davor aber schützt, ist an den kritischen Stellen, an denen der
> Zeiger zugewiesen wird, korrekten Code zu schreiben.

Na ja, das ist ein wenig zu einfach gedacht. Ein Pointer wird ja nicht 
von sich aus ungültig. Aber du hast im Grunde schon recht.
Und im Grunde ging es auch nicht darum.
Es ging darum, dass dieses 'Idiom'

   if( Ptr )
     free( Ptr );

keinen Wert hat. Es schützt vor nichts. Es hilft einem nichts. Es ist 
(meistens) noch nicht einmal eine 'Optimierung' in irgendeiner Form. Es 
ist genau so gut wie ein simples

   free( Ptr );

Es hat die gleichen Probleme, die selben Stolperfallen. Kurz und gut: 
Die Abfrage bringt gar nichts. nientje, nada, nothing.

Und trotzdem sieht man sie häufig.

Ausgangspunkt der ganzen Story war ja die Fragestellung des OT

> Anders gefragt, wie bekommt man heraus, ob es sich bei einem
> berechneten Zeiger (auf eine Liste) um einen gültigen handelt?

bzw. seine Ergänzung

> Ok, dann habe ich das wohl mit einem Zeiger auf einen String
> verwechselt, wo eine True/False Prüfung das gewünschte bewirkt.

Und ich glaube in diesen beiden Sätzen im Prinzip genau dieses

   if( Ptr )
     free( Ptr );

wiedererkannt zu haben.
"Mach die Abfrage und mir kann nichts passieren."

Wohlgemerkt: Es handelt sich um den Fall, dass er Pointerarithmetik 
betreibt und hinterher sicher gehen will, dass der resultierende Pointer 
gültig ist. Das ist etwas anderes als eine Dereferenzierung über einen 
NULL Pointer. Dort macht es natürlich schon Sinn, sich gegen einen NULL 
Pointer zu schützen.

von P. S. (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:

> also das zurechtcasten des Ergebnisses von malloc.
> Tut das nicht, auch wenn man es des Öfteren sieht. Ihr könnt euch damit
> einen bösen Fehler verstecken!

Welchen?

von Rolf Magnus (Gast)


Lesenswert?

Für alle Funktionen, die nicht vorher deklariert worden sind, nimmt der 
Compiler automatisch als return-Typ int an. Wenn man nun das zum malloc 
gehörende #include <stdlib.h> vergisst, geht der Comiler auch bei dieser 
Funktion davon aus. Das heißt, daß dann der zurückgegebene Zeigerwert 
als int interpretiert und dann bei der Zuweisung von int wiederum in 
einen Zeiger konvertiert wird. Es gibt zwar Plattformen, auf denen die 
Konvertierung auch nur eine Uminterpretation der Bits ist, aber das ist 
nicht überall so. Ein gutes Beispiel für eine Plattform, wo das 
üblicherweise nicht so ist, ist der PC, wenn auch nur im 64bit-Modus. Da 
ist ein Zeiger nämlich doppelt so groß wie ein int und so würde bei der 
Zuweisung die Hälfte vom Zeiger abgeschnitten.  Der Cast sorgt dafür, 
daß der Compiler das auch kommentarlos so akzeptiert. Ohne den Cast muß 
der Compiler hier warnen. Mit dem Cast sagst du dem Compiler soviel wie: 
"Auch wenn du das für blödsinnig hältst und meinst, mich deshalb warnen 
zu müssen: Ich will das so, also halt die Klappe und mach's einfach".

von Klaus W. (mfgkw)


Lesenswert?

Das ist zwar so richtig, aber durch den cast bleibt malloc()
immer noch undeklariert.
Wenn jemand 1. stdlib.h nicht nimmt und 2. die Warnungen
wegen "implicit declaration" ignoriert, ist ihm eh nicht mehr zu helfen.
Das wäre für mich kein Grund, den cast weg zu lassen.

von Rolf Magnus (Gast)


Lesenswert?

> Das ist zwar so richtig, aber durch den cast bleibt malloc()
> immer noch undeklariert.

Ja, aber dann warnt einen der Compiler.

> Wenn jemand 1. stdlib.h nicht nimmt und 2. die Warnungen
> wegen "implicit declaration" ignoriert,

Dazu muß er sie erstmal kriegen. Der Cast sorgt dafür, daß man die 
Warnung eben nicht mehr kriegt.

> Das wäre für mich kein Grund, den cast weg zu lassen.

Was heißt "weg zu lassen"? Wozu wurde er überhaupt dazugefügt? Er ist an 
dieser Stelle völlig unnötig.

von Klaus W. (mfgkw)


Lesenswert?

Rolf Magnus schrieb:
>> Das ist zwar so richtig, aber durch den cast bleibt malloc()
>> immer noch undeklariert.
>
> Ja, aber dann warnt einen der Compiler.

Eben.
Der cast hilft nicht vor der Warnung wg. undeklariertem malloc().

>
>> Wenn jemand 1. stdlib.h nicht nimmt und 2. die Warnungen
>> wegen "implicit declaration" ignoriert,
>
> Dazu muß er sie erstmal kriegen. Der Cast sorgt dafür, daß man die
> Warnung eben nicht mehr kriegt.

Nein.
1
int main( int nargs, char **args )
2
{
3
4
  char *p = (char*)malloc(100);
5
  return 0;
6
}
liefert bei mir:
1
klaus@a64a:~ > gcc -Wall t.c
2
t.c: In function ‘main’:
3
t.c:4: warning: implicit declaration of function ‘malloc’
4
t.c:4: warning: incompatible implicit declaration of built-in function ‘malloc’
5
t.c:4: warning: unused variable ‘p’


>
>> Das wäre für mich kein Grund, den cast weg zu lassen.
>
> Was heißt "weg zu lassen"? Wozu wurde er überhaupt dazugefügt? Er ist an
> dieser Stelle völlig unnötig.

Lebensnotwendig ist er sicher nicht.
Aber erstens zeigt es, was man will (für den Leser), zweitens
schreibe ich viel in C++ und habe einen möglichst einheitlichen Stil.
Deshalb schreibe ich hier den cast.
Ohne den Anspruch, da missionieren zu wollen...

von P. S. (Gast)


Lesenswert?

Klaus Wachtler schrieb:

> Der cast hilft nicht vor der Warnung wg. undeklariertem malloc().

Darum bin ich wohl noch nie in diese toedliche Falle getappt ;-)

von Rolf Magnus (Gast)


Lesenswert?

> t.c:4: warning: implicit declaration of function ‘malloc’
> t.c:4: warning: incompatible implicit declaration of built-in function
> ‘malloc’

Ok, ist bei gcc mittlerweile Standard, weil er das schon eingebaut hat. 
War aber nicht immer so und ist nicht bei jedem Compiler so.

>> Was heißt "weg zu lassen"? Wozu wurde er überhaupt dazugefügt? Er ist
>> an dieser Stelle völlig unnötig.
>
> Lebensnotwendig ist er sicher nicht.
> Aber erstens zeigt es, was man will (für den Leser),

Inwiefern zeigt ein
1
    struct foo* p = malloc(sizeof(struct foo));

das weniger gut als die entsprechende Zeile mit Cast?

> zweitens schreibe ich viel in C++ und habe einen möglichst einheitlichen
> Stil.

In C++ brauche ich eigentlich sehr selten einen Cast. Da bestimmt nicht, 
weil ich statt malloc dann new verwende. Und wenn mal ein Cast vorkommt, 
dann ist es auch kein C-Style-Cast. Daher sehe ich an dieser Stelle 
keine Möglichkeit, einen Stil zu vereinheitlichen.

> Ohne den Anspruch, da missionieren zu wollen...

Och komm, wenn schon, denn schon ;-)

von Klaus W. (mfgkw)


Lesenswert?

Rolf Magnus schrieb:
>> t.c:4: warning: implicit declaration of function ‘malloc’
>> t.c:4: warning: incompatible implicit declaration of built-in function
>> ‘malloc’
>
> Ok, ist bei gcc mittlerweile Standard, weil er das schon eingebaut hat.
> War aber nicht immer so und ist nicht bei jedem Compiler so.

Gibt es noch andere Compiler?
In den letzten Jahren kam mir ehrlich gesagt nur gcc und MS-VC++
unter die Finger.

>
>>> Was heißt "weg zu lassen"? Wozu wurde er überhaupt dazugefügt? Er ist
>>> an dieser Stelle völlig unnötig.
>>
>> Lebensnotwendig ist er sicher nicht.
>> Aber erstens zeigt es, was man will (für den Leser),
>
> Inwiefern zeigt ein
>
>
1
>     struct foo* p = malloc(sizeof(struct foo));
2
>
>
> das weniger gut als die entsprechende Zeile mit Cast?

In diesem Beispiel sieht es natürlich auch ein Blinder mit Krückstock.

Aber leicht abgewandelt:
1
    struct foo* p = NULL;
2
3
    // ...
4
5
    // 2 Jahre gehen ins Land, man heiratet, lässt sich scheiden,
6
    // und dann kommt ein:
7
    p = malloc(sizeof(struct foo));

Mit cast wäre jetzt klarer, was man vorhat.

>
>> zweitens schreibe ich viel in C++ und habe einen möglichst einheitlichen
>> Stil.
>
> In C++ brauche ich eigentlich sehr selten einen Cast. Da bestimmt nicht,
> weil ich statt malloc dann new verwende. Und wenn mal ein Cast vorkommt,

Für Objekte ja, für Speicher nein.

> dann ist es auch kein C-Style-Cast. Daher sehe ich an dieser Stelle
> keine Möglichkeit, einen Stil zu vereinheitlichen.

Doch, wenn man denselben Code mal als C und mal C++ braucht.

>
>> Ohne den Anspruch, da missionieren zu wollen...
>
> Och komm, wenn schon, denn schon ;-)

ok, also:
Ohne cast ist Murks, wer das macht ist doof.


Aber im Ernst: ich behaupte ja nicht, daß der cast da nötig ist
und aus Karl-Theodor Maria Nikolaus Johann Jacob Philipp Franz
Joseph Sylvester Freiherr von und zu Guttenberg einen Mann
des Volkes macht.
Einen guten Grund gegen den cast kann ich allerdings nach wie
vor nicht erkennen.

von Rolf Magnus (Gast)


Lesenswert?

>> Ok, ist bei gcc mittlerweile Standard, weil er das schon eingebaut hat.
>> War aber nicht immer so und ist nicht bei jedem Compiler so.
>
> Gibt es noch andere Compiler?

Ja, wobei der einzige davon, den ich in letzter Zeit verwendet hab, was 
die Meldungen angeht, sowieso völlig unbrauchbar ist. Der scheint nur 
eine einzige Fehlermeldung zu kennen, nämlich "Syntax Error", und die 
meisten davon meldet er eine Zeile nach Ende der Datei.

> Mit cast wäre jetzt klarer, was man vorhat.

Naja, ich find's auch so klar, aber das ist eben Ansichtssache.

>> In C++ brauche ich eigentlich sehr selten einen Cast. Da bestimmt
>> nicht, weil ich statt malloc dann new verwende. Und wenn mal ein Cast
>> vorkommt,
>
> Für Objekte ja, für Speicher nein.

Warum? New wurde absichtlich so gemacht, daß es für beides geht. 
"Speicher" ist dann auch nur ein Array aus Objekten vom Typ unsigned 
char.

>> dann ist es auch kein C-Style-Cast. Daher sehe ich an dieser Stelle
>> keine Möglichkeit, einen Stil zu vereinheitlichen.
>
> Doch, wenn man denselben Code mal als C und mal C++ braucht.

Wenn ich es als C schreibe, compiliere ich es auch als C. Man kann es ja 
immer noch problemlos mit C++-Code zusammenlinken. Nur der Header muß 
natürlich passend geschrieben sein.

> Einen guten Grund gegen den cast kann ich allerdings nach wie
> vor nicht erkennen.

Naja, mit modernen Compilern schwindet dieser Grund wohl. Ich mache da 
trotzdem keinen Cast, weil ich auch keinen Grund dafür erkennen kann.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:

> Aber leicht abgewandelt:
>
>
1
>     struct foo* p = NULL;
2
> 
3
>     // ...
4
> 
5
>     // 2 Jahre gehen ins Land, man heiratet, lässt sich scheiden,
6
>     // und dann kommt ein:
7
>     p = malloc(sizeof(struct foo));
8
>
>
> Mit cast wäre jetzt klarer, was man vorhat.

Mit einem ordentlichen Bezeichner statt "p" ebenfalls. ;-)  Einen
Namen wie "i" oder "p" würde ich nur benutzen, wenn das alles
übersichtlich auf eine 24x80-Bildschirmseite passt.

Eine hart "in die Finger verdrahtete" Initialisierung lokaler
Variablen (wie hier das "= NULL") habe ich mir auch abgewöhnt.
Manchmal vertut man sich irgendwo in der Logik und ist der Meinung,
man hätte alle Fälle abgedeckt, da ist die Compilerwarnung "could
possibly be used uninitialized" sehr nützlich, sowas aufzudecken.
Wenn man dagegen "aus Prinzip" überall Initialiserungen vorsieht,
ist für den Compiler immer alles in Butter.

von P. S. (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Einen Namen wie "i" oder "p" würde ich nur benutzen, wenn das alles
> übersichtlich auf eine 24x80-Bildschirmseite passt.

Nicht mal dann, zumindest nicht, solange ich noch schneller tippen als 
denken kann.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:

> Aber leicht abgewandelt:
>
>
1
>     struct foo* p = NULL;
2
> 
3
>     // ...
4
> 
5
>     // 2 Jahre gehen ins Land, man heiratet, lässt sich scheiden,
6
>     // und dann kommt ein:
7
>     p = malloc(sizeof(struct foo));
8
>
>
> Mit cast wäre jetzt klarer, was man vorhat.

Dem kann ich nicht folgen, inwiefern man da jetzt irgendetwas besser 
sieht.
Ich würde sogar die Empfehlung aussprechen und nach Möglichkeit auf die 
Angabe von Datentypen im sizeof beim malloc-Argument komplett zu 
verzichten und nach Möglichkeit immer alles über die Variable 
abzuwickeln.
1
     p = malloc( sizeof( *p ) );

bedeutet: Allokiere ein Objekt, so dass p auf dieses Objekt zeigt. p 
weiß schon selber auf welchen Objekttyp es zeigen kann, das braucht mich 
hier absolut nicht zu interessieren. Weder das /sizeof(struct foo)/ noch 
der Cast des Returnwertes vom malloc tragen IMHO da irgendetwas zu 
irgendeiner Klärung bei.

Jeder mag das halten wie er will. Ich werde auch weiterhin die 
Empfehlung aussprechen, keinen Cast zu benutzen, der nicht absolut 
notwendig ist. Und an dieser Stelle ist er nicht notwendig. Lasse ich 
ihn weg und habe vergessen den Header reinzuholen, der malloc 
deklariert, dann habe ich einen Error (Assignment makes pointer from 
integer). Mache ich einen Cast, dann habe ich den Error je nach Compiler 
auf entweder nichts oder eine Warnung reduziert. Aber der Code 
compiliert in diesem Fall durch und kann fehlerhaftes Verhalten 
hervorrufen wenn sizeof(int) != sizeof(void*).

von Ulf R. (roolf)


Lesenswert?

Karl heinz Buchegger schrieb:

> Daher ist in C bei so etwas
>
>     if( ptr )
>       free( ptr );
>
> bzw. in C++
>
>     if( ptr )
>       delete ptr;
>
> die Abfrage des Pointer-Wertes eine sinnlose Aktion (in 99% aller Fälle)

Ein bisschen sinnvoller würde es, wenn der Pointer dann wirklich 
ungültig gemacht würde:
1
if (ptr) {
2
  free (ptr);
3
  ptr = 0;
4
}

von Matthias L. (matze88)


Lesenswert?

Ulf Rolf schrieb:
> Ein bisschen sinnvoller würde es, wenn der Pointer dann wirklich
> ungültig gemacht würde:
> if (ptr) {
>   free (ptr);
>   ptr = 0;
> }
1
free(ptr);
2
ptr = NULL;

Ist da aber exakt gleichbedeutend...

Auch möchte ich gerne nochmal Karl Heinz Buchegger unterstützen:
1
p = malloc( sizeof( *p ) );

Ist wohl die beste, am besten lesbare und portabelste Schreibweise. So 
kann ich den Typ von p ändern und es funktioniert trotzdem noch.

Back to Topic: Ist der Fragesteller noch mit an Board und kann sich 
melden, wenn ihm noch irgendwas unklar ist?

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.