So konvertieren Sie Programmparameter von argv
zu int64_t
? atoi()
ist nur für 32-Bit-Ganzzahlen geeignet.
Wie konvertiere ich eine Zeichenfolge in int64_t?
pmichna
Ahmed Masud
Es gibt einige Möglichkeiten, dies zu tun:
strtoll(str, NULL, 10);
Dies ist POSIX C99-konform.
Sie können auch strtoimax verwenden; die den folgenden Prototyp hat:
strtoimax(const char *str, char **endptr, int base);
Das ist nett, weil es immer mit dem lokalen intmax_t funktioniert … Das ist C99 und Sie müssen es einschließen <inttypes.h>
-
@OliCharlesworth ja, du hast Recht, aber die Besetzung ist als Hinweis da, um daran zu erinnern, dass das OP, wenn es sie analysieren möchte, sie durch einen Zeiger auf eine Zeichenfolge ersetzen kann, das ist alles.
– Ahmed Masud
8. Juni 2013 um 19:32 Uhr
-
@AhmedMasud Dafür ist die Dokumentation da. Oder vielleicht ein Kommentar. Bitte keine überflüssigen Casts einsetzen, sie sind überflüssig, können sogar Fehler verbergen und verbergen vor allem verringern sie die Lesbarkeit.
– Benutzer529758
8. Juni 2013 um 19:34 Uhr
-
@Ahmed: Ah, fair genug. Beachten Sie, dass es wahrscheinlich auch erwähnenswert ist, dass dieser Ansatz davon ausgeht
int64_t
ist das gleiche wielong long
.– Oliver Charlesworth
8. Juni 2013 um 19:34 Uhr
-
@OliCharlesworth: Es wird nicht davon ausgegangen, dass sie gleich sind, nur das
long long
groß genug ist, um einen beliebigen Wert zu speichernint64_t
, was fast stimmt, aber nicht ganz. Siehe meine Antwort.– R.. GitHub HÖR AUF, EIS ZU HELFEN
8. Juni 2013 um 19:46 Uhr
-
Wenn das Ergebnis im Bereich von liegt
int64_t
, diese Methode ist in Ordnung. Wenn das Ergebnis außerhalb des Bereichs von liegen würdeint64_t
erfordert dieser Ansatz nicht veröffentlichte zusätzliche Arbeit, um solche Probleme tragbar zu erkennen.– chux – Wiedereinsetzung von Monica
20. Mai 2016 um 16:01 Uhr
Chux – Wiedereinsetzung von Monica
Ein C99-konformer Versuch.
[edit] beschäftigt @R. Korrektur
// Note: Typical values of SCNd64 include "lld" and "ld".
#include <inttypes.h>
#include <stdio.h>
int64_t S64(const char *s) {
int64_t i;
char c ;
int scanned = sscanf(s, "%" SCNd64 "%c", &i, &c);
if (scanned == 1) return i;
if (scanned > 1) {
// TBD about extra data found
return i;
}
// TBD failed to scan;
return 0;
}
int main(int argc, char *argv[]) {
if (argc > 1) {
int64_t i = S64(argv[1]);
printf("%" SCNd64 "\n", i);
}
return 0;
}
-
+1 für den cleveren Gedanken zu verwenden
sscanf
aber es istSCNd64
nichtPRId64
, das brauchst du. Mir ist auch unklar obsscanf
muss sich bei Überlauf gut verhalten.– R.. GitHub HÖR AUF, EIS ZU HELFEN
8. Juni 2013 um 20:52 Uhr
-
@R .. Ich denke das
scanf()
Familie ist angegeben, wie zu arbeitenstrtol()
Familie von Funktionen. Bei letzterem verursachen ReichweitenfehlerERANGE
eingelagert werdenerrno
. (C11-Entwurf 7.8.2.3.3). Also einerrno
Prüfung eingebaut werden könnte.– chux – Wiedereinsetzung von Monica
8. Juni 2013 um 21:10 Uhr
-
@chux Bist du sicher? Entsprechend Dies
SCNd64
ist fürscanf
undPRId64
ist fürprintf
.– pmichna
10. Juni 2013 um 22:24 Uhr
-
@chux: Ich kann nirgendwo finden
scanf
ist angegeben, sich so zu verhalten. Die Spezifikation fürscanf
nicht einmal eine Vorgabe, wie der zu ermittelnde Wert gespeichert wird. Es gibt nur das erwartete Format der Eingabe und den erforderlichen Typ der Ausgabe an, aber nichts über das Konvertierungsverfahren. Dies scheint ein Versehen zu sein, hinterlässt jedoch viele Unklarheiten in Bezug auf die Fehlerbehandlung …– R.. GitHub HÖR AUF, EIS ZU HELFEN
10. Juni 2013 um 22:29 Uhr
-
@R.. Mein Vorschlag, dass die
scanf()
Familie ist angegeben, wie zu arbeitenstrtol()
stammt aus C11 Draft 7.21.6.2.12: “d
Stimmt mit einer optional vorzeichenbehafteten dezimalen Ganzzahl überein, deren Format dasselbe ist wie erwartet für die Betreffsequenz der strtol-Funktion mit dem Wert 10 für das Basisargument … “. Mein Eclipse C Indigo Service Release 1-Compiler setzt dies nichterrno
nach ERANGE überscanf()
. Also mindestens 1 Compiler tut dies. Obwohlstrtol()
setzterrno
ich, wie Sie, sehe Mehrdeutigkeit in Bezug aufscanf()
Fehlerbehandlung. Vielleicht wissen es andere?– chux – Wiedereinsetzung von Monica
11. Juni 2013 um 3:05 Uhr
strtoll
wandelt es in a um long long
das ist normalerweise ein 64-Bit-Int.
Benutzer, die von einer Websuche kommen, sollten dies ebenfalls berücksichtigen std::stoll
.
Es beantwortet diese ursprüngliche Frage nicht streng effizient für a const char*
aber viele Benutzer werden eine haben std::string
Sowieso. Wenn Sie sich nicht um Effizienz kümmern, sollten Sie eine implizite Konvertierung erhalten (basierend auf der benutzerdefinierten Konvertierung mit dem Einzelargument std::string
Konstrukteur) zu std::string
auch wenn du eine hast const char*
.
Es ist einfacher als std::strtoll
was immer 3 Argumente erfordert.
Es sollte werfen, wenn die Eingabe keine Zahl ist, aber sehen Sie sich diese Kommentare an.
Dies zu 100% portabel zu machen, ist ein bisschen schwierig. long long
muss mindestens 64 Bit umfassen, muss aber nicht unbedingt ein Zweierkomplement sein, sodass es möglicherweise nicht dargestellt werden kann -0x7fffffffffffffff-1
und damit verwenden strtoll
könnte ein gebrochenes Eckgehäuse haben. Das gleiche Problem gilt für strtoimax
. Was Sie stattdessen tun könnten, ist führendes Leerzeichen zu verbrauchen (wenn Sie führendes Leerzeichen zulassen möchten) und zuerst nach dem Vorzeichen suchen und dann verwenden strtoull
oder strtoumax
die beide Werte bis zum vollen positiven Bereich von unterstützen müssen int64_t
. Sie können dann das Zeichen anwenden:
unsigned long long x = strtoull(s, 0, 0);
if (x > INT64_MAX || ...) goto error;
int64_t y = negative ? -(x-1)-1 : x;
Diese Logik wurde geschrieben, um alle Überlauffälle zu vermeiden.
-
Aber um fair zu sein, bezweifle ich
int64_t
ist auf jedem System mit einer vorzeichenbehafteten Darstellung definiert, die sich vom Zweierkomplement unterscheidet. Ich denke auch, dass dies einer der Hauptgründe dafür ist, dass die Integer-Typen mit exakter Breite optional sind.– au
8. Juni 2013 um 19:58 Uhr
-
Ich dachte, POSIX benötigt es, aber tatsächlich benötigt POSIX nur 8-, 16- und 32-Bit-Typen mit exakter Größe.
int64_t
unduint64_t
sind bei POSIX optional. Also stimme ich zuint64_t
Es ist unwahrscheinlich, dass es auf Systemen existiert, auf denenlong
oderlong long
ist nicht geeignet.– R.. GitHub HÖR AUF, EIS ZU HELFEN
8. Juni 2013 um 20:05 Uhr
-
Unklar, wie “Logik geschrieben wird, um alle Überlauffälle zu vermeiden”.
-(x-1)-1
oder-x
funktionieren genauso wiex
ist ein breiter Typ ohne Vorzeichen.– chux – Wiedereinsetzung von Monica
20. Mai 2016 um 16:03 Uhr
-
@chux: Ich glaube, ich meinte
-((int64_t)x-1)-1
. Macht das mehr Sinn?– R.. GitHub HÖR AUF, EIS ZU HELFEN
20. Mai 2016 um 19:00 Uhr
-
-((int64_t)x-1)-1
macht doch mehr sinn(int64_t)x
ist immer noch signierter Integer-Überlauf. Vielleicht-1-((int64_t)-(x+1))
?– chux – Wiedereinsetzung von Monica
20. Mai 2016 um 20:34 Uhr
Wie konvertiere ich eine Zeichenfolge in int64_t?
Das einfachste
#include <stdlib.h>
int64_t value = atoll(some_string); // Lacks error checking. UB on overflow.
Besser
long long v = strtoll(s, NULL, 0); // No reported errors, well defined on overflow.
Robust: Erstellen Sie eine Hilfsfunktion, um alle Probleme zu erkennen.
#include <stdbool.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
// Return error flag
bool my_strtoi64(int64_t *value, const char *s) {
// Maybe add a s==NULL, value==NULL checks.
char *endptr;
errno = 0;
long long v = strtoll(s, &endptr, 0);
// Optional code for future growth of `long long`
#if LLONG_MIN < INT64_MIN || LLONG_MAX > INT64_MAX
if (v < INT64_MIN) {
v = INT64_MIN;
errno = ERANGE;
} else if (v > INT64_MAX) {
v = INT64_MAX;
errno = ERANGE;
#endif
*value = (int64_t) v;
if (s == endptr) { // No conversion, v is 0
return true;
}
if (errno == ERANGE) { // Out of range
return true;
}
if (errno) { // Additional implementations specific errors
return true;
}
while (isspace(*(unsigned char* )endptr)) { // skip trailing white-space
endptr++;
}
if (*endptr) { // Non-numeric trailing text
return true;
}
return false; // no error
}
-
Aber um fair zu sein, bezweifle ich
int64_t
ist auf jedem System mit einer vorzeichenbehafteten Darstellung definiert, die sich vom Zweierkomplement unterscheidet. Ich denke auch, dass dies einer der Hauptgründe dafür ist, dass die Integer-Typen mit exakter Breite optional sind.– au
8. Juni 2013 um 19:58 Uhr
-
Ich dachte, POSIX benötigt es, aber tatsächlich benötigt POSIX nur 8-, 16- und 32-Bit-Typen mit exakter Größe.
int64_t
unduint64_t
sind bei POSIX optional. Also stimme ich zuint64_t
Es ist unwahrscheinlich, dass es auf Systemen existiert, auf denenlong
oderlong long
ist nicht geeignet.– R.. GitHub HÖR AUF, EIS ZU HELFEN
8. Juni 2013 um 20:05 Uhr
-
Unklar, wie “Logik geschrieben wird, um alle Überlauffälle zu vermeiden”.
-(x-1)-1
oder-x
funktionieren genauso wiex
ist ein breiter Typ ohne Vorzeichen.– chux – Wiedereinsetzung von Monica
20. Mai 2016 um 16:03 Uhr
-
@chux: Ich glaube, ich meinte
-((int64_t)x-1)-1
. Macht das mehr Sinn?– R.. GitHub HÖR AUF, EIS ZU HELFEN
20. Mai 2016 um 19:00 Uhr
-
-((int64_t)x-1)-1
macht doch mehr sinn(int64_t)x
ist immer noch signierter Integer-Überlauf. Vielleicht-1-((int64_t)-(x+1))
?– chux – Wiedereinsetzung von Monica
20. Mai 2016 um 20:34 Uhr
Fritz Pom
Das hat bei mir mit einem anderen int64-Typ funktioniert, und ich mag den sauberen C++-Stil:
std::istringstream iss(argv[i]);
int64_t i64;
iss >> i64;
Möglicherweise erhalten Sie einen Kompilierungsfehler: operator<<... is not defined.
Und ich weiß nicht, was passiert, wenn argv[i] enthält “Hallo”.
-
Wenn die Konvertierung fehlschlägt (wie bei “HALLO”), erhalten Sie 0. Aber das Fail-Bit wird auch gesetzt, also sollten Sie iss.fail() aufrufen, um dies zu überprüfen.
– Zitrax
21. Oktober 2018 um 15:43 Uhr
Auf einer Plattform, wo
int64_t
ist das gleiche wielong
dann ist der schnelle Hacky-Weg einfach zu verwendenatol()
.– Oliver Charlesworth
8. Juni 2013 um 19:18 Uhr
Die Verwendung von sscanf mit einem passenden Spezifizierer für int64_t kann eine plattformunabhängige Methode bereitstellen.
– chux – Wiedereinsetzung von Monica
8. Juni 2013 um 19:48 Uhr
Etwas pedantischer Punkt: Was Sie fragen, ist nicht, wie man konvertiert
char *
zuint64_t
(Wenn Sie das wollten, wäre eine einfache Umwandlung die Antwort), aber stattdessen, wie man eine Zeichenfolge konvertiert, auf die die zeigtchar *
das eine Zahl in einer menschenorientierten Textkonvention wie eine Dezimalzeichenfolge darstellt, toint64_t
.– R.. GitHub HÖR AUF, EIS ZU HELFEN
8. Juni 2013 um 20:41 Uhr