Zeiger Auf Ausreichend Platz Als Cee Idiom
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Unbestreitbar ist es eine gängige Sprachwendung in der Sprache C [CeeIdioms], dass ein Zeiger an eine Funktion übergeben wird, und dass es Teil der Schnittstelle dieser Funktion ist, dass der Zeiger auf Speicherplatz zeigen muss, der gross genug ist, um seinen Zweck zu erfüllen.
| #include <string.h>
void StrInsStr(char *string, char const * toInsert)
{
size_t insertLength = strlen(toInsert);
memmove(string + insertLength, string, strlen(string) + 1);
memcpy(string, toInsert, insertLength);
} |
|
|
Diese Funktion ist ein Beispiel für eine solche Funktion. Wer diese Funktion sicher verwenden möchte muss vor dem Aufruf sicherstellen, dass der erste Parameter auf einen Speicherplatz zeigt, der genügend Platz für die Konkatenation beider Parameter enthält.
Die Information, wie gross dieser Speicherplatz eigentlich ist, wird an die Funktion in C üblicherweise nicht mitgeliefert, so dass die Funktion diese Vorbedingung nicht selbst prüfen kann.
Eine Dokumentation dieser Vorbendingung für die Funktion
wäre nur dann möglich, wenn der verfügbare Speicherplatz an die Funktion übergeben würde:
| #include <string.h>
#include <assert.h>
void StrInsStr2(char *string, size_t stringSize,
char const * toInsert)
{
size_t insertLength = strlen(toInsert);
assert(strlen(string) + insertLength < stringSize);
memmove(string + insertLength, string, strlen(string) + 1);
memcpy(string, toInsert, insertLength);
} |
|
|
So, wie die Verwendung von Zeigern in C üblich ist, muss die Dokumentation der Vorbedingung vor dem Aufruf der Funktion erfolgen:
| {
char buffer[18] = "world";
char *prefix = "Hello, ";
assert(strlen(buffer) + strlen(prefix) < sizeof buffer);
StrInsStr(buffer, prefix);
} |
|
|
Ist das eine Redewendung, mit der die Gemeinde der C-Entwickler zufrieden sein sollte? Wenn es nicht nur um eine Dokumentation, sondern um eine Behandlung der Situation "Zu wenig Platz" im produktiven Programm geht, stellt sich eine sehr ähnliche Frage: Soll diese Behandlung des fehlenden Speicherplatzes wirklich bei jedem Aufruf der Funktion erfolgen? Wäre ist nicht sinnvoller, auch bei Funktionen, bei denen der Speicherbedarf im voraus berechenbar ist (wie StrInsStr), immer mit Paaren von Zeigern und Längenangaben zu arbeiten, sozusagen als feste Redewendung? --KurtWatzka
- Umgekehrt wird ein Schuh draus. Selbstverständlich "soll diese Behandlung des fehlenden Speicherplatzes" nicht "bei jedem Aufruf der Funktion erfolgen", nämlich z. B. dort nicht, wo es eben bekannt ist, dass genügend Speicherplatz bereitgestellt ist. -- VolkerGlave
- Selbstverständlich kann ZeigerMitLängeAlsCeeIdiom sinnvoll sein. Dieses Idiom wird teilweise schon in der Standardbibliothek verwendet, ist auch teilweise bei Entwicklern gebräuchlich. -- hl
- Ein konkrektes Beispiel, wie ein Aufruf aussehen würde, bei dem sichergestellt ist, dass genügend Speicherplatz vorhanden ist, wäre sicher nützlich zum Verständnis dieser Gegenrede. Auch als kleine Erinnerung daran, dass Speicherplatz ein Thema bei einer solchen Funktion ist finde ich einen entsprechenden Parameter einer solchen Funktion nützlich. assert() ist ja keine Prüfung einer Bedingung, sondern lediglich eine Dokumentation einer Annahme, die in der Funktion, oder bei deren Aufruf, gemacht wird. assert() erzeugt keinen Code, wenn NDEBUG definiert ist, und soll so behandelt werden, als ob es nie Code erzeugen würde. Ein angenehmer Nebeneffekt von assert() ist, dass bei nicht definiertem NDEBUG eben doch Code erzeugt wird, der prüft, ob Annahmen eingehalten werden. Das ändert nichts daran, dass assert() eine Annahme dokumentiert und nicht prüft. --kw
- Beispiel:
| /* Sei dies irgendeine Quelldatei foo.c */
#include <string.h>
/* Dies sei so eine fragliche Funktion, die davon ausgeht, dass
"ausreichend" Speicherplatz bereitgestellt ist. */
static void append_hallo(char* s)
{
strcat(s, "hallo");
}
[... nun ein die fragliche Funktion nutzendes Codefragment ...]
/* Sei die in dieser Anweisung genutze Funktion von solcher
Art, dass sie - falls sie ueberhaupt zurueckkehrt - garantiert
eine Zeichenkette mit 100 Zeichen Speicherplatz liefert. */
char* s = get_string100();
s[0] = 0;
/* Verwendung der fraglichen Funktion, von der wir eben
nicht wuenschen, dass sie pruefe, ob "ausreichend" Speicher-
platz vorhanden ist, weil wir dies als Aufrufer selbst
garantieren. Warum wir dies nicht wuenschen, muss nicht
erklaert werden, es reicht zu sagen, dass dies hin und
wieder - und das variiert bzgl. der Haeufigkeit von Anwendung
zu Anwendung zwischen "nie" und "fast immer" - eben so ist.
In allen Anwendungsfaellen ausser dem "nie" ist das fragliche
Idiom als solches also wohl ok. */
append_hallo(s);
[...] |
|
|
- -- vgl
- Ergänzung: Im übrigen ist ja sehr wohl das oben angesprochene alternative Idiom "mit Paaren von Zeigern und Längenangaben zu arbeiten" ebenfalls gängig (allerdings eben nicht "immer"). Beispiele aus string.h:
| char* strcpy(char*, const char*);
char* strncpy(char*, const char*, size_t);
char* strcat(char*, const char*);
char* strncat(char*, const char*, size_t);
int strcmp(const char*, const char*);
int strncmp(const char*, const char*, size_t); |
|
|
- -- vgl
Diskussionen:
Siehe auch:
KategorieC KategorieCee
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 29. November 2007 8:49 (diff))