Sind strtol, strtod unsicher?

Lesezeit: 4 Minuten

Es scheint, dass strtol() und strtod() Erlauben (und zwingen) Sie effektiv, Konstanz in einer Zeichenfolge zu verwerfen:

#include <stdlib.h>
#include <stdio.h>

int main() {
  const char *foo = "Hello, world!";
  char *bar;
  strtol(foo, &bar, 10); // or strtod(foo, &bar);
  printf("%d\n", foo == bar); // prints "1"! they're equal
  *bar="X"; // segmentation fault
  return 0;
}

Oben habe ich selbst keine Güsse durchgeführt. Jedoch, strtol() im Grunde werfen meine const char * in ein char * für mich, ohne Warnungen oder irgendetwas. (Tatsächlich würde es Ihnen nicht erlauben, zu tippen bar Als ein const char *und erzwingt so die unsichere Typänderung.) Ist das nicht wirklich gefährlich?

Ich würde das vermuten, weil die Alternative schlechter war. Angenommen, der Prototyp wurde geändert, um hinzuzufügen const:

long int strtol(const char *nptr, const char **endptr, int base);

Angenommen, wir möchten eine nicht konstante Zeichenfolge analysieren:

char str[] = "12345xyz";  // non-const
char *endptr;
lont result = strtol(str, &endptr, 10);
*endptr="_";
printf("%s\n", str);  // expected output: 12345_yz

Aber was passiert, wenn wir versuchen, diesen Code zu kompilieren? Ein Compilerfehler! Es ist eher nicht intuitiv, aber Sie können a nicht implizit konvertieren char ** zu einem const char **. Siehe die C++ FAQ Lite für eine ausführliche Erklärung warum. Technisch gesehen wird dort von C++ gesprochen, aber die Argumente gelten gleichermaßen für C. In C/C++ dürfen Sie nur implizit von “pointer to Typ” bis “Zeiger auf const Typ” auf der höchsten Ebene: Die Konvertierung, die Sie durchführen können, ist von char ** zu char * const *oder äquivalent von “Zeiger auf (Zeiger auf char)” zu “Zeiger auf (const Zeiger auf char)”.

Da ich vermuten würde, dass das Analysieren einer nicht konstanten Zeichenfolge viel wahrscheinlicher ist als das Analysieren einer konstanten Zeichenfolge, würde ich dies weiter postulieren const-Inkorrektheit für den unwahrscheinlichen Fall ist besser, als den allgemeinen Fall zu einem Compilerfehler zu machen.

Benutzer-Avatar
Steve Jessop

Ja, und andere Funktionen haben das gleiche “const-laundering”-Problem (z. B. strchr, strstr, all das).

Aus genau diesem Grund fügt C++ Überladungen hinzu (21.4:4): die Funktionssignatur strchr(const char*, int) wird durch die beiden Deklarationen ersetzt:

const char* strchr(const char* s, int c);
      char* strchr(      char* s, int c);

Aber natürlich können Sie in C nicht beide const-korrekten Versionen mit demselben Namen haben, also erhalten Sie den const-incorrect-Kompromiss.

C++ erwähnt keine ähnlichen Überladungen für strtol und strtod, und mein Compiler (GCC) hat sie tatsächlich nicht. Ich weiß nicht, warum nicht: die Tatsache, dass Sie nicht implizit casten können char** zu const char** (zusammen mit dem Fehlen einer Überladung) erklärt es für C, aber ich sehe nicht ganz, was an einer C++-Überladung falsch wäre:

long strtol(const char*, const char**, int);

  • stlport bietet diese Überladung (und einige andere).

    – Alex Cohn

    3. März 2013 um 11:29 Uhr

Benutzer-Avatar
Jonathan Leffler

Das ‘const char *’ für das erste Argument bedeutet das strtol() wird die Zeichenfolge nicht ändern.

Was Sie mit dem zurückgegebenen Zeiger machen, ist Ihre Sache.

Ja, es könnte als Typsicherheitsverletzung angesehen werden; C++ würde die Dinge wahrscheinlich anders machen (obwohl, soweit ich das beurteilen kann, ISO/IEC 14882:1998 definiert <cstdlib> mit der gleichen Signatur wie in C).

  • C++ definiert strtol (und alles andere in cstdlib) mit der gleichen Signatur wie C, aber nicht alles in cstring und cwchar.

    – Steve Jessop

    15. Juni 2009 um 0:56 Uhr

Ich habe einen Compiler, der beim Kompilieren im C++-Modus Folgendes bereitstellt:

extern "C" {
long int strtol(const char *nptr, const char **endptr, int base);
long int strtol(char *nptr, char **endptr, int base);
}

Offensichtlich lösen sich beide in dasselbe Link-Zeit-Symbol auf.

BEARBEITEN: Nach dem C++-Standard sollte dieser Header nicht kompiliert werden. Ich vermute, der Compiler hat dies einfach nicht überprüft. Die Definitionen erschienen tatsächlich so in den System-Header-Dateien.

1112170cookie-checkSind strtol, strtod unsicher?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy