Sollte ich static_cast oder reinterpret_cast verwenden, wenn ich eine Leere * auf was auch immer wirke?

202

Sowohl static_cast als auch reinterpret_cast scheinen gut zu funktionieren, um void * in einen anderen Zeigertyp umzuwandeln. Gibt es einen guten Grund, einander vorzuziehen?

Andy
quelle
78
@anon Anscheinend hast du vorher noch nie mit POSIX-Threads gearbeitet.
user470379
7
@ user470379 Wow ... genau aus diesem Grund bin ich bei SO auf diese Frage gestoßen! Hervorragende Beobachtung :-).
Oger Psalm33

Antworten:

148

Verwendungstatic_cast : Es ist die engste Besetzung, die genau beschreibt, welche Konvertierung hier vorgenommen wird.

Es gibt ein Missverständnis, dass die Verwendung reinterpret_castbesser zusammenpassen würde, da dies bedeutet, dass die Typensicherheit vollständig ignoriert und nur von A nach B geworfen wird.

Dies beschreibt jedoch nicht die Wirkung von a reinterpret_cast. Hat vielmehr reinterpret_casteine Reihe von Bedeutungen, für die alle besagen, dass „das von durchgeführte Mapping reinterpret_castimplementierungsdefiniert ist“. [5.2.10.3]

Aber im besonderen Fall des Castings von void*bis T*zum Mapping ist der Standard völlig genau definiert; nämlich einem typlosen Zeiger einen Typ zuzuweisen, ohne dessen Adresse zu ändern.

Dies ist ein Grund zu bevorzugen static_cast.

Darüber hinaus und wohl wichtiger ist die Tatsache, dass jede Verwendung von reinterpret_castgeradezu gefährlich ist, da sie alles wirklich in etwas anderes umwandelt (für Zeiger), während sie static_castviel restriktiver ist und somit ein besseres Schutzniveau bietet. Dies hat mich bereits vor Fehlern bewahrt, bei denen ich versehentlich versucht habe, einen Zeigertyp in einen anderen zu zwingen.

Konrad Rudolph
quelle
8

Das ist eine schwierige Frage. Einerseits macht Konrad einen hervorragenden Punkt in Bezug auf die Spezifikationsdefinition für reinterpret_cast , obwohl es in der Praxis wahrscheinlich dasselbe tut. Wenn Sie dagegen zwischen Zeigertypen wechseln (wie dies beispielsweise bei der Indizierung im Speicher über ein char * üblich ist), generiert static_cast einen Compilerfehler und Sie müssen ohnehin reinterpret_cast verwenden .

In der Praxis verwende ich reinterpret_cast, weil es die Absicht der Cast-Operation besser beschreibt. Sie könnten sich durchaus dafür einsetzen, dass ein anderer Operator nur Zeiger-Neuinterpretationen festlegt (die die gleiche zurückgegebene Adresse garantieren), aber es gibt keine im Standard.

Nick
quelle
6
" Unterschiedlicher Operator, der nur Zeiger-Neuinterpretationen festlegt (was garantiert, dass dieselbe Adresse zurückgegeben wird) " Hug? Dieser Operator ist reinterpret_cast !
Neugieriger
2
@curiousguy Entspricht nicht dem Standard. reinterpret_cast garantiert NICHT, dass dieselbe Adresse verwendet wird. Nur wenn Sie_cast von einem Typ zum anderen und dann wieder zurück interpretieren , erhalten Sie dieselbe Adresse zurück, mit der Sie begonnen haben.
ClydeTheGhost
0

Ich schlage vor, immer die schwächste Besetzung zu verwenden.

reinterpret_castkann verwendet werden, um einen Zeiger auf a zu werfen float. Je strukturbrechender die Besetzung ist, desto mehr Aufmerksamkeit erfordert ihre Verwendung.

Im Falle von char*würde ich eine Besetzung im C-Stil verwenden, bis wir welche haben reinterpret_pointer_cast, weil sie schwächer ist und nichts anderes ausreicht.

Pavel Radzivilovsky
quelle
2
" reinterpret_cast kann verwendet werden, um einen Zeiger auf einen Float zu setzen. " Sicher nicht!
Neugieriger
3
Wahrscheinlichfloat f = *reinterpret_cast<const float*>(&p);
Ben Voigt
2
@BenVoigt Das ist Casting zwischen Zeigern; einer von ihnen war zufällig ein Float-Zeiger.
Nodakai
5
@ BenVoigt der "gesamte Ausdruck" ist allerdings keine Besetzung. Der Ausdruck besteht aus einer Dereferenzierung, die auf eine Besetzung angewendet wird. Sie haben behauptet, es sei möglich, einen Zeiger auf zu setzen float, was falsch ist. Der Ausdruck Abgüsse void **zu const float *und verwendet dann einen dereferenzieren Betrieb (das ist kein cast), zu konvertieren const float *zu float.
MM
2
@ BenVoigt Sie haben diesen Code als Antwort auf die Frage "Wie mache ich ...?" Angeboten. Als dann jemand sagte, dass der Code zwischen Zeigern wechselt (was er tut), sagten Sie "Nein"
MM
-7

Meine persönliche Präferenz basiert auf Code-Kenntnissen wie folgt:

void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();

oder

typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();

Am Ende machen beide dasselbe, aber static_cast scheint in einer Middleware-App-Umgebung angemessener zu sein, während eine Neuinterpretation der Besetzung eher etwas ähnelt, das Sie meiner Meinung nach in einer Bibliothek auf niedrigerer Ebene sehen würden.

Robert Gould
quelle