81

I have grown accustomed to strtod and variants. I am wondering why there is no strtoi shipped with <stdlib.h>. Why is it that the integer type is left out of this party?

Specifically I am asking why there is not a version of atoi with the safety features of strtod?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Eli
  • 2,041
  • 4
  • 18
  • 20

6 Answers6

51

strtol() converts a string to an integer, a long integer but an integer nevertheless. There is atoi() but it should be avoided in most cases due to the fact that it lacks a mechanism for error reporting from invalid input.

Wiz
  • 2,145
  • 18
  • 15
  • 11
    When the range of `long` exceeds the range of `int`, `strtol()` does not set `errno` nor return `INT_MIN/MAX` on `int` only overflow negating the value of that safety feature. – chux - Reinstate Monica Dec 12 '15 at 17:40
  • 3
    @chux not sure what you are trying to say. Of course it's not an error if the value passed exceeds the range of int. – Wiz Dec 20 '15 at 01:01
  • 10
    As the answer does not detail how to use `strtol()` when trying to convert to an `int`, pointing out that strings that represent a value outside the `int` range, (but not `long`) do not set `errno` nor get a limited value. This is different behavior than strings that represent a value outside the `long` range: which does set `errno` and get a limited value. – chux - Reinstate Monica Dec 20 '15 at 02:44
  • And so for the same reason, `strtol()` should be avoid when converting to `int` due to the fact that it lacks a mechanism for error reporting from input that would overflow an `int`. – Jonathan Wood Sep 17 '19 at 16:31
  • @chux-ReinstateMonica I did understand what you mean in the first place: When using `strtol` to convert a string to an `int`, and the value in the string is exceeding the range of an `int` - `long` has simultaneously a wider range than `int` - there is no error or anything thrown, which could alarm the coder, which causes of course safety lacks. But I do not understand what do you mean with *"...strings that represent a value outside the `int` range, (but not `long`)..."* - What is an example for a value which is exceeding the range of an `int` but isn´t in the range of a `long` but... – RobertS supports Monica Cellio Feb 14 '20 at 14:50
  • @chux-ReinstateMonica also isn´t exceeding the range of `long`? What I mean is `long` should kind of "encapsulate" the range of an `int`, **if** it it has a wider range than an `int` but how can a value which isn´t in the range of an `int` can´t be an `long` without being superior the `long` range? – RobertS supports Monica Cellio Feb 14 '20 at 14:50
  • @chux-ReinstateMonica To clarify my concern even a bit more: The cited phrase of *"...strings that represent a value outside the int range, (but not long)... - This is different behavior than strings that represent a value outside the `long` range:"* says to me that there shall be a kind of gap between the `int` and the `long` range, **if** the `long` hasn´t the same range of an `int`. – RobertS supports Monica Cellio Feb 14 '20 at 15:02
  • Yes, the range of `long` _may_ exceed `int` - or it may just the same. It is up to the implementation. `int` may be 16,32,64,... bit, `long` is at least `int` size, may be 32 or 64... bit. – chux - Reinstate Monica Feb 15 '20 at 02:21
  • 1
    Does not answer OP's question. – vesperto Nov 09 '21 at 10:55
  • 1
    Late, I know, but for completion: On 64-bit linux `long` *is* 64 bits wide while `int` only 32, so any value in the range of `[2^31; 2^63)` or its negative counter part of [-2^63, -2^31) would need to produce an error for `int` but doesn't... – Aconcagua Aug 12 '22 at 13:26
49

Why is there no strtoi in stdlib.h?

No critical need.

In early C, there was not a standard signed integer type wider than long and all narrower conversions, like int, could be made from strtol() - as done below.

These and their unsigned counterparts are now missing C functions and a design shortcoming in the current standard C library (C17/18).


On many systems, long and int have the same range and so there is a reduced need for a separate strtoi(). atoi() fills the need for quick and dirty code to convert to an int, but can lack error detection. On error, atoi() incurs undefined behavior (UB). There also is no strto_short() nor strto_signchar(), etc.

It is fairly easy to create a substitute strtoi(). Simplifications exist.

#include <errno.h>
#include <limits.h>
#include <stdlib.h>

static long str2subrange(const char *s, char **endptr, int base, 
    long min, long max) {
  long y = strtol(s, endptr, base);
  if (y > max) {
    errno = ERANGE;
    return max;
  }
  if (y < min) {
    errno = ERANGE;
    return min;
  }
  return y;
}

// OP's goal
int str2i(const char *s, char **endptr, int base) {
  #if INT_MAX == LONG_MAX && INT_MIN == LONG_MIN
    return (int) strtol(s, endptr, base);
  #else
    return (int) str2subrange(s, endptr, base, INT_MIN, INT_MAX);
  #endif
}

short str2short(const char *s, char **endptr, int base) {
  return (short) str2subrange(s, endptr, base, SHRT_MIN, SHRT_MAX);
}

signed char str2schar(const char *s, char **endptr, int base) {
  return (signed char) str2subrange(s, endptr, base, SCHAR_MIN, SCHAR_MAX);
}

#include <stdint.h>
int16_t str2int16(const char *s, char **endptr, int base) {
  return (int16_t) str2subrange(s, endptr, base, INT16_MIN, INT16_MAX);
}

[Edit 2021]

To avoid conflicts with Future library directions, names changed from strto...() to str2...().
2 implying to.

Function names that begin with str, mem, or wcs and a lowercase letter may be added to the declarations in the <string.h> header. C17dr § 7.31.13 1

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 5
    Not sure why this isn't the accepted answer. Somehow your comment about the accepted answer didn't get sufficient traction. – Mad Physicist Nov 02 '18 at 06:07
  • @MadPhysicist I was 4 year later and OP has not been around since 3 years before this answer. Yet it is slowly rising. – chux - Reinstate Monica Nov 02 '18 at 06:10
  • Also note that BSD provides strtonum() which more or less does just this, although you can't specify the base. https://linux.die.net/man/3/strtonum – Jetski S-type Nov 13 '18 at 01:26
  • 2
    `strtonum` has counterproductive semantics: it returns `0` on all errors, returning min or max on overflow is a feature of `strtol()` which makes it easy to determine the cause of the problem. The man page claims that *The existing alternatives, such as `atoi(3)` and `strtol(3)`, are either impossible or difficult to use safely.* This is true for `atoi()` but there is no difficulty in using `strtol()` safely. – chqrlie May 19 '21 at 17:57
  • "On many systems, long and int have the same range" - On 64-bit Windows, they are equal. On 64-bit LInux/unix-like, they are not. https://en.cppreference.com/w/cpp/language/types – Åsmund Mar 29 '22 at 11:52
  • @Åsmund True. On many embedded systems, billions per year these days, most are 32-bit systems with same size `long, int`. Many (I suspect about 20%) have 32-bit `long` and 16-bit `int`. – chux - Reinstate Monica Mar 29 '22 at 14:19
3

This is what I have been using.

long long_val;
int  int_value;

errno = 0;
long_val = strtol (theString, NULL, 10);
if (errno)
   handle_error;
if ((long) someIntMin > long_val || long_val > (long) someIntMax)
   handle_invalid;
int_value = (int) long_val;
Tim
  • 4,790
  • 4
  • 33
  • 41
Marc K.
  • 69
  • 1
  • 7
3

The integer isn't left out of the party: there is strtol, which converts a string to a long, which is an integer type.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 1
    is it just me or does this answer completely miss the point of the question? The OP is not asking about "integer type", but rather `int` type. – xdavidliu Aug 06 '23 at 12:36
-5

It's call atoi. See also Wikipedia for details, including its successor strol.

mtrw
  • 34,200
  • 7
  • 63
  • 71
  • 8
    `atoi` should not be used. – James McNellis May 30 '11 at 23:02
  • 3
    @James McNellis _atoi should not be used_ -- you've made this statement as if your reason should be obvious, but as several answers all seem to agree that atoi() is the right solution it must not be that obvious. Would you would like to fill everyone in on why you feel atoi should not be used or is it best left a mystery? – mah May 30 '11 at 23:07
  • 1
    @mah: If `atoi` returns `0`, `INT_MIN`, or `INT_MAX`, you have no way of knowing whether the conversion succeeded. – James McNellis May 30 '11 at 23:11
  • @mah - According to the wikipedia page: "It is impossible to tell whether the string holds valid sequence of digits that represents the number 0 or invalid number as the function returns 0 in both cases. The newer function strtol does not have this deficiency." – mtrw May 30 '11 at 23:11
  • 4
    @James McNellis: It's actually much worse than that - the specification is *"If the value of the result cannot be represented, the behaviour is undefined."*. – caf May 30 '11 at 23:33
  • 4
    Indeed, using `atoi` is theoretically almost as bad as using `gets`: unless you have very strict control over the input, it results in **undefined behavior**. Fortunately, most implementations don't actually take this liberty, and `atoi` simply produces `unsigned`-like wrapping on overflow, but you should not rely on that. Just don't use `atoi`. – R.. GitHub STOP HELPING ICE May 31 '11 at 00:10
  • Using sscanf for integers is just as bad. – Demi Nov 23 '13 at 07:32
-5

Don't overlook the SEE ALSO section of your manpages :)

SEE ALSO
       atof(3), atoi(3), atol(3), strtol(3), strtoul(3)

You're looking for atoi(3). :)

sarnold
  • 102,305
  • 22
  • 181
  • 238