Как преобразовать строку в int64_t?

Как преобразовать параметр программы из argv в int64_t? atoi() подходит только для 32-битных целых чисел.

7 ответов

Решение

Соответствующая попытка C99.

[править] занято @R. коррекция

// 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;
}

Есть несколько способов сделать это:

  strtoll(str, NULL, 10);

Это POSIX C99-совместимый.

Вы также можете использовать strtoimax; который имеет следующий прототип:

 strtoimax(const char *str, char **endptr, int base);

Это хорошо, потому что он всегда будет работать с локальным intmax_t ... Это C99, и вам нужно включить <inttypes.h>

Пользователи, пришедшие с веб-поиска, должны также учитывать std::stoll,

Он не дает точного ответа на этот оригинальный вопрос const char* но многие пользователи будут иметь std::string в любом случае. Если вы не заботитесь об эффективности, вы должны получить неявное преобразование (основанное на пользовательском преобразовании с использованием одного аргумента). std::string конструктор) в std::string даже если у вас есть const char*,

Это проще чем std::strtoll который всегда будет требовать 3 аргумента.

Должен выдать, если на входе не число, но посмотрите эти комментарии.

strtoll преобразует его в long long который обычно является 64-битным Int.

Делать это на 100% переносимо немного сложно. long long должен быть не менее 64 бит, но не обязательно должен быть дополнением до двух, так что он не сможет представлять -0x7fffffffffffffff-1и, таким образом, используя strtoll может иметь сломанный угловой чехол. Та же проблема относится к strtoimax, Вместо этого вы можете использовать начальный пробел (если вы хотите разрешить начальный пробел) и сначала проверить наличие знака, а затем использовать strtoull или же strtoumaxлюбой из которых требуется для поддержки значений вплоть до полного положительного диапазона int64_t, Затем вы можете применить знак:

unsigned long long x = strtoull(s, 0, 0);
if (x > INT64_MAX || ...) goto error;
int64_t y = negative ? -(x-1)-1 : x;

Эта логика написана, чтобы избежать всех случаев переполнения.

Это сработало для меня с другим типом int64, и мне нравится чистый стиль C++:

std::istringstream iss(argv[i]);
int64_t i64;
iss >> i64;

Вы можете получить ошибку компиляции: operartor<<... не определен.

И я не знаю, что произойдет, если argv[i] содержит "HALLO".

Как преобразовать строку в int64_t?

Простейший

      #include <stdlib.h>
int64_t value = atoll(some_string);  // lacks error checking.  UB on overflow

Лучше

      long long v = strtoll(s, NULL, 0);  // No reported errors, well defined on overflow

Надежный: создайте вспомогательную функцию для обнаружения всех проблем.

      #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 trail white-space
    endptr++;
  }
  if (*endptr) { // Non-numeric trailing text
    return true;
  }
  return false; // no error
}
Другие вопросы по тегам