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

- 4,800
- 13
- 53
- 90
-
On a platform where `int64_t` is the same as `long`, then the quick hacky way is to just use [`atol()`](http://en.cppreference.com/w/c/string/byte/atoi). – Oliver Charlesworth Jun 08 '13 at 19:18
-
1Using sscanf with a matching specifier for int64_t may provide a platform independent method. – chux - Reinstate Monica Jun 08 '13 at 19:48
-
3Slightly pedantic point: what you're asking is not how to convert `char *` to `int64_t` (if you wanted that, a simple cast would be the answer) but instead how to convert a string pointed to by the `char *`, which represents a number in some human-oriented textual convention like a decimal string, to `int64_t`. – R.. GitHub STOP HELPING ICE Jun 08 '13 at 20:41
7 Answers
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>

- 21,655
- 3
- 33
- 58
-
@OliCharlesworth yeah you are right, but the the cast is there as a hint to remind that if the OP wants to parse it that they can replace it with a pointer to a string that's all. – Ahmed Masud Jun 08 '13 at 19:32
-
1@AhmedMasud That's what the documentation is for. Or maybe a comment. Please don't put in superfluous casts, they're redundant, may even hide hide errors and **most importantly, they decrease readability.** – Jun 08 '13 at 19:34
-
@Ahmed: Ah, fair enough. Note that it's also probably worth mentioning that this approach assumes that `int64_t` is the same as `long long`. – Oliver Charlesworth Jun 08 '13 at 19:34
-
@OliCharlesworth: It doesn't assume they're the same, just that `long long` is sufficiently large to store any value of `int64_t`, which is almost true but not quite. See my answer. – R.. GitHub STOP HELPING ICE Jun 08 '13 at 19:46
-
When the result is in range of `int64_t`, this method is OK. When the result would be outside the range of `int64_t`, this approach needs unposted additional work to portable detect such problems. – chux - Reinstate Monica May 20 '16 at 16:01
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;
}

- 143,097
- 13
- 135
- 256
-
2+1 for the clever thought to use `sscanf`, but it's `SCNd64`, not `PRId64`, that you need. I'm also unclear on whether `sscanf` has to behave well on overflow. – R.. GitHub STOP HELPING ICE Jun 08 '13 at 20:52
-
@R.. I think the `scanf()` family is specified to work like `strtol()` family of functions. In the latter, range errors cause `ERANGE` to be stored in `errno`. (C11 draft 7.8.2.3.3). So an `errno` test could be incorporated. – chux - Reinstate Monica Jun 08 '13 at 21:10
-
2@chux Are you sure? According to [this](http://pubs.opengroup.org/onlinepubs/009604599/basedefs/inttypes.h.html) `SCNd64` is for `scanf` and `PRId64` is for `printf`. – pmichna Jun 10 '13 at 22:24
-
@chux: I can't find anywhere `scanf` is specified to behave like that. The specification for `scanf` doesn't even state any requirement for how the value to be determined is stored. It just specifies the expected format of the input and required type of the output, but nothing about the conversion procedure. This seems to be an oversight, but it leaves a lot of ambiguity in regards to error handling... – R.. GitHub STOP HELPING ICE Jun 10 '13 at 22:29
-
@R.. My suggestion that the `scanf()` family is specified to work like `strtol()` comes from C11 Draft 7.21.6.2.12: "`d` Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtol function with the value 10 for the base argument … ". My Eclipse C Indigo Service Release 1 compiler does set `errno` to ERANGE via `scanf()`. So at least 1 compiler does so. Although `strtol()` sets `errno`, I, like you, see ambiguity in regards to `scanf()` error handling. Maybe others may know? – chux - Reinstate Monica Jun 11 '13 at 03:05
-
@chux: The text you cited describes the input sequences that the conversion specifier matches, but not the manner in which it is converted. While the intent seems to be that the value is obtained as if the matching sequence were converted by `strtol`, that's not explicitly stated, and in fact there is no `strtol` variant corresponding to smaller-than-`long` conversions like `%d` or `%hd`. – R.. GitHub STOP HELPING ICE Jun 11 '13 at 03:09
-
So, if `%d` were converted as if by `strtol`, it's possible that overflow of `long` would not happen, but the result might not fit into `int`, in which case it's not at all clear what should happen. (Clamping like `strtol` does? Implementation-defined conversion like in C expressions? Error?) – R.. GitHub STOP HELPING ICE Jun 11 '13 at 03:11
-
ISO/IEC 9899:2011 §7.21.6.2 **The `fscanf` function** ¶10 _…Unless assignment suppression was indicated by a `*`, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined._ Thus `scanf()` has UB on overflow — also listed in Annex J.2 Undefined behaviour. – Jonathan Leffler Sep 01 '17 at 06:02
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.

- 1,286
- 18
- 25
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.

- 208,859
- 35
- 376
- 711
-
1But to be fair I doubt `int64_t` is defined on any system with a signed representation different than two's complement. I also think that's one of the major reason for the exact-width integer types to be optional. – ouah Jun 08 '13 at 19:58
-
I thought POSIX required it, but in fact POSIX only requires 8, 16, and 32-bit exact-sized types. `int64_t` and `uint64_t` are optional on POSIX. So I agree `int64_t` is unlikely to exist on systems where `long` or `long long` isn't suitable. – R.. GitHub STOP HELPING ICE Jun 08 '13 at 20:05
-
Unclear how "logic is written to avoid all overflow cases". `-(x-1)-1` or `-x` work the same as `x` is an wide unsigned type. – chux - Reinstate Monica May 20 '16 at 16:03
-
@chux: I think I meant `-((int64_t)x-1)-1`. Does that make more sense? – R.. GitHub STOP HELPING ICE May 20 '16 at 19:00
-
`-((int64_t)x-1)-1` makes more sense, yet `(int64_t)x` is still signed integer overflow. Perhaps `-1-((int64_t)-(x+1))`? – chux - Reinstate Monica May 20 '16 at 20:34
-
@chux: No; `x+1` could be greater than `INT64_MAX`, or could be zero, and in either case, `-(x+1)` is equal to `x+1`, and either gives you the wrong result or an implementation-defined conversion when you cast to `int64_t`. On the other hand, `(int64_t)x` is well-defined because the above line just tested that `x` is in the range of `int64_t`. – R.. GitHub STOP HELPING ICE May 20 '16 at 22:11
-
However it looks like my code is missing the logic to actually handle the `INT64_MIN` case right... – R.. GitHub STOP HELPING ICE May 20 '16 at 22:15
-
`x+1` is not greater than `INT64_MAX` as I, like you in your earlier comment was referring to the left half of `:`, (when `negative` is true - (`x<0`)) OTOH, perhasp I am missing the condition when `negative` is set. IAC, good to work with you. – chux - Reinstate Monica May 20 '16 at 22:15
-
-
@chux: The intent is that `negative` is set based on whether you read a `'-'` character before the number. `x<0` is always false because it has unsigned type. – R.. GitHub STOP HELPING ICE May 21 '16 at 04:40
-
The more I look at it the more I think my answer just has major flaws that make it no better than using `strtoll`, and likely worse. – R.. GitHub STOP HELPING ICE May 21 '16 at 04:42
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 trailing white-space
endptr++;
}
if (*endptr) { // Non-numeric trailing text
return true;
}
return false; // no error
}

- 143,097
- 13
- 135
- 256
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".

- 11
- 1
-
If the conversion fails (like with "HALLO") you will get 0. But the fail bit will also be set, so you should call iss.fail() to check that. – Zitrax Oct 21 '18 at 15:43