[C++] Wann gilt ein Zeiger als dereferenziert?
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
[C++] Wann gilt ein Zeiger als dereferenziert?
Hi,
eine Frage, die ich mir immer wieder Stelle, ist: Was genau ist die Dereferenzierung eines Zeigers? Der bloße Aufruf des *ptr-Operators? Oder erst ein Zugriff auf die Adresse, die im Zeiger steht? Genauer:
void foo(int &) { }
int * ptr = nullptr;
foo(*ptr);
Hier wird der Nullzeiger in eine Referenz umgewandelt, die dann aber nicht benutzt wird. Gilt das bereits als Dereferenzierung? Ist der Quelltext standardkonform?
eine Frage, die ich mir immer wieder Stelle, ist: Was genau ist die Dereferenzierung eines Zeigers? Der bloße Aufruf des *ptr-Operators? Oder erst ein Zugriff auf die Adresse, die im Zeiger steht? Genauer:
void foo(int &) { }
int * ptr = nullptr;
foo(*ptr);
Hier wird der Nullzeiger in eine Referenz umgewandelt, die dann aber nicht benutzt wird. Gilt das bereits als Dereferenzierung? Ist der Quelltext standardkonform?
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
afaik jaKrishty hat geschrieben:Gilt das bereits als Dereferenzierung?
Ich würde sagen: Undefined BehaviourKrishty hat geschrieben:Ist der Quelltext standardkonform?
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
http://en.wikipedia.org/wiki/Reference_(C%2B%2B)
in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Ja; das sind triftige Gründe.
Ich frage, weil ich meine Windows-Handles gern als Referenzen herumreiche, und das alte Lied ist, dass CreateFile() nicht 0 als Fehlerwert zurückgibt, sondern INVALID_HANDLE_VALUE. Meine Überlegung war, dass es ziemlich schmutzig würde, falls mal ein Datei-Handle mit dem Wert 0 zurückkäme.
Ich kann es aber von der anderen Seite lösen: CreateFile() scheint zwar 0 nicht als Fehlerwert zurückzugeben, aber auch nicht als gültiges Handle. Scheinbar war das zuletzt unter Windows 98 der Fall, wenn man COM-Ports geöffnet hat. Ich kann also unter Windows NT annehmen, dass niemals ein gültiges Handle mit dem Wert 0 existiert – das erleichtert Vieles und erledigt auch die Frage.
In jedem Fall danke dafür, dass ihr meine Neugier gestillt habt!
Ich frage, weil ich meine Windows-Handles gern als Referenzen herumreiche, und das alte Lied ist, dass CreateFile() nicht 0 als Fehlerwert zurückgibt, sondern INVALID_HANDLE_VALUE. Meine Überlegung war, dass es ziemlich schmutzig würde, falls mal ein Datei-Handle mit dem Wert 0 zurückkäme.
Ich kann es aber von der anderen Seite lösen: CreateFile() scheint zwar 0 nicht als Fehlerwert zurückzugeben, aber auch nicht als gültiges Handle. Scheinbar war das zuletzt unter Windows 98 der Fall, wenn man COM-Ports geöffnet hat. Ich kann also unter Windows NT annehmen, dass niemals ein gültiges Handle mit dem Wert 0 existiert – das erleichtert Vieles und erledigt auch die Frage.
In jedem Fall danke dafür, dass ihr meine Neugier gestillt habt!
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Ein wenig riskant ist es ja schon, weil man ja nicht weiß was Windows da intern macht. Aber die Chancen, dass deine hoffentlich harmlose Annahme korrekt ist stehen relativ gut, und zwar wegen CloseHandle(). Wenn du CloseHandle() mit NULL oder INVALID_HANDLE_VALUE aufrufst, so wird GetLastError() dir ERROR_INVALID_HANDLE liefern. Für ein wirklich ungültiges Handle jedoch, schmeißt CloseHandle() eine Exception (kannst du sehen wenn du z.B. mal schnell einen Mutex erzeugst und das Handle zweimal schließt). Dieses Verhalten lässt einen schon vermuten wie der Source-Code von CloseHandle() anfängt... aber es sind halt tatsächlich nur Vermutungen.Krishty hat geschrieben:Ich kann also unter Windows NT annehmen, dass niemals ein gültiges Handle mit dem Wert 0 existiert – das erleichtert Vieles und erledigt auch die Frage.
- Artificial Mind
- Establishment
- Beiträge: 802
- Registriert: 17.12.2007, 17:51
- Wohnort: Aachen
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Laut http://msdn.microsoft.com/en-us/library ... s.85).aspx wird folgendes definiert:
Das könnte dann auch implizieren, dass ein HANDLE von 0 nicht gültig ist (sondern nur für spezielle Handles, wie das HWND 0 genutzt wird).
Weitere Indizien dafür finden sich in http://msdn.microsoft.com/de-de/library ... s.90).aspx.
damit ist ein Handle doch ein void* oder?A handle to an object.
This type is declared in WinNT.h as follows:Code: Alles auswählen
typedef PVOID HANDLE;
Das könnte dann auch implizieren, dass ein HANDLE von 0 nicht gültig ist (sondern nur für spezielle Handles, wie das HWND 0 genutzt wird).
Weitere Indizien dafür finden sich in http://msdn.microsoft.com/de-de/library ... s.90).aspx.
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Nein; ob es einen Wert für ungültig gibt und welcher das ist, hängt von der Art des Handle ab...Krishty hat geschrieben:Ich kann also unter Windows NT annehmen, dass niemals ein gültiges Handle mit dem Wert 0 existiert
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
INVALID_HANDLE_VALUE mag ein ungültiger Wert für CreateFile() sein, aber nicht der Einzige (sondern nur das einzige Signal). CreateFile() wird unter NT niemals 0 zurückgeben, weil alle Handles bei 4 beginnen (die symbolischen bei 3). 0 trat unter Windows 9x auf, aber nicht unter NT. Einige Leute behaupten, dass es in früheren NT-Versionen stdin angesteuert hat (zusätzlich zu GetStdHandle(STDIN)), aber selbst wenn, wird das nie bei einer von mir geöffneten Datei auftreten (selbst wenn ich stdin öffne, bekomme ich ein anderes, nicht-0-Handle zurück).dot hat geschrieben:Nein; ob es einen Wert für ungültig gibt und welcher das ist, hängt von der Art des Handle ab...Krishty hat geschrieben:Ich kann also unter Windows NT annehmen, dass niemals ein gültiges Handle mit dem Wert 0 existiert
Direkte Garantien gibt es nicht, aber viele Indirekte:
- Inside Windows 2000 schreibthttp://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2005-05/msg00387.html hat geschrieben:An object handle is an index into a process-specific handle table, pointed to by the executive process (EPROCESS) block (described in Chapter 6). The first handle index is 4, the second 8, and so on.
- Windows’ Kernel-Debugger kann keine Details zu Handle 0 anzeigen; stattdessen löst es das Anzeigen *aller* Handles aus.
- Offenbar implementieren die meisten NT-Funktionen 0 als Spezialfall. Das gilt nur für Windows XP, aber auf höheren Versionen hat ebenfalls noch nie jemand ein 0-Handle entdecken können (Process Explorer!):http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2005-05/msg00444.html hat geschrieben:On any NT-derived platform, 0 (zero) can never be a valid handle value. A zero handle will either result in an error or special behavior. For example, the native ZwCreateProcess() service has a section handle argument, which is always supplied by win32's CreateProcess(). If that handle is zero, ZwCreateProcess() will use the fork() semantics for process creation [which is to copy the address space of the parent]. For another example, ZwTerminateProcess() takes -1, 0 or a valid process handle; and the zero handle will _not_ terminate the process, unlike the other two cases, but again do something very special. This can be repeated for just about any native OS routine that accepts handles; comparison against zero is ubiquitous in the OS code, so if any valid handle somehow had such a value, you would not be able to perform any "regular" operation on this handle.
The INVALID_HANDLE_VALUE, which is -1, is in fact a valid handle, which means "this process". Of course, ReadFile() will fail with this handle, because the object type is wrong, just like ReadFile() will fail on a perfectly valid handle of a mutex, a thread, etc.
CloseHandle() does indeed fail when given a bad handle. It will fail on both -1 and 0: -1 cannot be closed, and 0 is just wrong. When CloseHandle() fails, it checks whether a debugger is attached to the process, in which case it raises an exception.
The Old New Thing — The dialog manager, part 4: The dialog loop hat geschrieben:So many people make this mistake that we had to put this app hack into the core OS. It would be pointless to make a shim for it since that would mean that thousands of apps would need to be shimmed.
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Hier hast du noch einen Indikator aus dem .NET-Framework, für die sichere Benutzung von Win32 Handles.
http://msdn.microsoft.com/de-de/library ... .110).aspx
Aber selbst die Existenz dieser Klasse (und ihrer Beschreibung) ist keine Garantie. Hast du denn keine anderen Möglichkeiten mit denen du happy wärst?
http://msdn.microsoft.com/de-de/library ... .110).aspx
Aber selbst die Existenz dieser Klasse (und ihrer Beschreibung) ist keine Garantie. Hast du denn keine anderen Möglichkeiten mit denen du happy wärst?
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Naja – eben gegen INVALID_HANDLE_VALUE testen, aber nur in den Fällen, wo es auch zurückgegeben wird. Das ist mir zu hässlich und zu unintuitiv. Eine Wrapper-Klasse wäre mir zu viel Code. Ich könnte auch einfach 1 zum Handle addieren wenn ich es rumreiche und 1 subtrahieren bevor ich es benutze – aber das wäre zu viel Overhead.
Eigentlich bin ich happy – CreateFile() wird niemals 0 zurückgegeben, also kann ich diesen Wert als eigene Markierung verwenden, die mit allen anderen Handles und Zeigersemantiken konform ist:
auto result = CreateFileW(…);
if(INVALID_HANDLE_VALUE == result) {
return NULL;
}
return result;
…
if(NULL != handle) {
CloseHandle(handle);
}
Eigentlich bin ich happy – CreateFile() wird niemals 0 zurückgegeben, also kann ich diesen Wert als eigene Markierung verwenden, die mit allen anderen Handles und Zeigersemantiken konform ist:
auto result = CreateFileW(…);
if(INVALID_HANDLE_VALUE == result) {
return NULL;
}
return result;
…
if(NULL != handle) {
CloseHandle(handle);
}
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Code: Alles auswählen
#pragma once
#include <utility>
#include "platform.h"
namespace Win32
{
template <typename T, T null_value, void (&close)(T)>
class handle
{
private:
handle(const handle&);
handle& operator =(const handle&);
T h;
public:
typedef T handle_type;
static const T null_value;
handle(T handle = null_value)
: h(handle)
{
}
handle(handle&& h)
: h(h.h)
{
h.h = null_value;
}
~handle()
{
if (h != null_value)
close(h);
}
operator T() const { return h; }
handle& operator =(handle&& h)
{
swap(*this, h);
return *this;
}
void reset(T handle = null_value)
{
if (h != null_value)
close(h);
h = handle;
}
T release()
{
T handle = h;
h = null_value;
return handle;
}
friend void swap(handle& a, handle& b)
{
using std::swap;
swap(a.h, b.h);
}
};
template <typename T, T null_value, void (&close)(T)>
const T handle<T, null_value, close>::null_value = null_value;
inline void closeHandle(HANDLE h)
{
CloseHandle(h);
}
}
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Siehst du? 70 Zeilen mehr als meins ;)
- B.G.Michi
- Establishment
- Beiträge: 163
- Registriert: 07.03.2006, 20:38
- Alter Benutzername: B.G.Michi
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Einmal geschrieben (oder STRG-C + STRG+V) für immer aus dem Sinn. Verwendet Handles so wie sie gedacht sind, keine Leistungseinbußen und in jedem fall standardkonform.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Wäre das erste Mal ;)B.G.Michi hat geschrieben:Einmal geschrieben (oder STRG-C + STRG+V) für immer aus dem Sinn.
Tue ich das nicht?Verwendet Handles so wie sie gedacht sind
Bei mir denn?keine Leistungseinbußen
Meins nicht?und in jedem fall standardkonform.
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
exception safe :P
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Ausnahmen wirft die WinAPI nicht; darum habe ich da auch keinen Bedarf :-)dot hat geschrieben:exception safe :P
Wie sieht es mit symbolischen Handles aus? Die darf man nicht schließen (The Old New Thing – What are the conventions for managing standard handles?); ansonsten verhalten sie sich aber wie jedes andere Datei-Handle auch …
Und da fällt mir ein versteckter Hinweis zur Null-Duldung auf:
If the value is INVALID_HANDLE_VALUE, then there is no active file. (You might also have decided to use NULL as your special value, but INVALID_HANDLE_VALUE works better here because that is the conventional sentinel value for file handles.)
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Nicht ganz korrekt. CloseHandle() kann beispielsweise Exceptions werfen. In diesem speziellen Fall aber nur wenn ein Debugger attached ist.Krishty hat geschrieben:Ausnahmen wirft die WinAPI nicht; darum habe ich da auch keinen Bedarf :-)
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Das sind aber strukturierte Ausnahmen und keine C++-Ausnahmen; Destruktoren würden dabei sowieso nicht aufgerufen werden (von ein paar sehr alten Compiler-Einstellungen, wo catch(...) auch auf SEH reagiert, abgesehen). Halt genau wie keine D’toren ablaufen falls du eine Zugriffsverletzung oder eine Division durch Null auslöst.
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Ja, da hast du recht.Krishty hat geschrieben:Das sind aber strukturierte Ausnahmen und keine C++-Ausnahmen;
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Aber das, was du mit "..." symbolisiert hast wirft möglicherweise, oder returned... :PKrishty hat geschrieben:Ausnahmen wirft die WinAPI nicht; darum habe ich da auch keinen Bedarf :-)dot hat geschrieben:exception safe :P
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Wann gilt ein Zeiger als dereferenziert?
Bei mir nicht ;)