Wie konvertiere ich eine Zeichenfolge in int64_t?

Lesezeit: 8 Minuten

Benutzer-Avatar
pmichna

So konvertieren Sie Programmparameter von argv zu int64_t? atoi() ist nur für 32-Bit-Ganzzahlen geeignet.

  • Auf einer Plattform, wo int64_t ist das gleiche wie longdann ist der schnelle Hacky-Weg einfach zu verwenden atol().

    – 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 * zu int64_t (Wenn Sie das wollten, wäre eine einfache Umwandlung die Antwort), aber stattdessen, wie man eine Zeichenfolge konvertiert, auf die die zeigt char *das eine Zahl in einer menschenorientierten Textkonvention wie eine Dezimalzeichenfolge darstellt, to int64_t.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    8. Juni 2013 um 20:41 Uhr

Benutzer-Avatar
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 wie long 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 speichern int64_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ürde int64_terfordert 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

Benutzer-Avatar
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 sscanfaber es ist SCNd64nicht PRId64, das brauchst du. Mir ist auch unklar ob sscanf 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 arbeiten strtol() Familie von Funktionen. Bei letzterem verursachen Reichweitenfehler ERANGE eingelagert werden errno. (C11-Entwurf 7.8.2.3.3). Also ein errno 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ür scanf und PRId64 ist für printf.

    – pmichna

    10. Juni 2013 um 22:24 Uhr

  • @chux: Ich kann nirgendwo finden scanf ist angegeben, sich so zu verhalten. Die Spezifikation für scanf 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 arbeiten strtol() 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 nicht errno nach ERANGE über scanf(). Also mindestens 1 Compiler tut dies. Obwohl strtol() setzt errnoich, wie Sie, sehe Mehrdeutigkeit in Bezug auf scanf() 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-1und 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 strtoumaxdie 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 und uint64_t sind bei POSIX optional. Also stimme ich zu int64_t Es ist unwahrscheinlich, dass es auf Systemen existiert, auf denen long oder long 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 wie x 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 und uint64_t sind bei POSIX optional. Also stimme ich zu int64_t Es ist unwahrscheinlich, dass es auf Systemen existiert, auf denen long oder long 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 wie x 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


Benutzer-Avatar
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

1350760cookie-checkWie konvertiere ich eine Zeichenfolge in int64_t?

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

Privacy policy