Pregunta

How to convert program parameter from argv to int64_t? atoi() is suitable only for 32 bit integers.

¿Fue útil?

Solución 2

A C99 conforming attempt.

[edit] employed @R. correction

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

Otros consejos

There are a few ways to do it:

  strtoll(str, NULL, 10);

This is POSIX C99 compliant.

you can also use strtoimax; which has the following prototype:

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

This is nice because it will always work with the local intmax_t ... This is C99 and you need to include <inttypes.h>

strtoll converts it to a long long which is usually a 64-bit int.

Users coming from a web search should also consider std::stoll.

It doesn't strictly answer this original question efficiently for a const char* but many users will have a std::string anyways. If you don't care about efficiency you should get an implicit conversion (based on the user-defined conversion using the single-argument std::string constructor) to std::string even if you have a const char*.

It's simpler than std::strtoll which will always require 3 arguments.

It should throw if the input is not a number, but see these comments.

Doing this 100% portably is a little bit tricky. long long is required to be at least 64 bits, but need not necessarily be twos complement, so it might not be able to represent -0x7fffffffffffffff-1, and thus using strtoll could have a broken corner case. The same issue applies to strtoimax. What you could do instead is consume leading space (if you want to allow leading space) and check for the sign first, then use strtoull or strtoumax, either of which is required to support values up to the full positive range of int64_t. You can then apply the sign:

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

This logic is written to avoid all overflow cases.

This worked for me with a different int64 type, and I like the clean C++ style:

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

You may get an compile error: operartor<<... is not defined.

And I don't know what happens, if argv[i] contains "HALLO".

How to convert string to int64_t?

The simplest

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

Better

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

Robust: Create a helper function to detect all problems.

#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
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top