C strtol – String to Long

Yesterday I wrote about the atoi function for converting ascii to integers or strings to integers. I also hinted that using the strtol function, or string to long can do everything that atoi does, but with more features. In fact, I also mentioned that atoi is essentially deprecated and should no longer be used. Lets take a look at strtol.

Advantages of strtol

The strtol function has a few advantages over the atoi function, including:

  1. strtol – will remove any whitespace at the start of the string if any exists.
  2. strtol – will set errno on error.
  3. strtol – provides support for any base from 2 to 36 inclusive.
  4. strtol – can identify negatives values within the string ‘-’ as negative.

strtol Function Prototype and Example

As I always say, an example always makes understanding a bit easier. The function prototype for strtol is:

#include <stdlib.h>
 
long int strtol(const char * str, char ** endptr, int base);

The first argument is the string to convert. The second argument is a reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value. This parameter can also be a NULL pointer, in which case it is not used. In most cases you can simply use the NULL pointer, unless your string has multiple values separated by spaces, then you must pass the endptr to the next iteration of the function. Finally, the third argument is the base in which to use. If you have a binary string then base 2 is your choice, or if you are working with integers then base 10 is your game, base 16 for hexadecimal and so on. Easy!

For your viewing pleasure, a C example:

#include <stdio.h>
#include <stdlib.h>
 
int main ()
{
  char basic_str[] = "8887";
  char data_string[] = "1234 1a2b3c4e -10101010 0xdeadbeef";
  char *end_char;
  long int basic_1, d1, d2, d3, d4;
 
  // Basic conversion
  basic_1 = strtol(basic_str, NULL, 10);
  fprintf(stdout, "Basic string %ld\n", basic_1);  
 
  // Using the endptr
  d1 = strtol(data_string,&end_char,10);
  d2 = strtol(end_char,&end_char,16);
  d3 = strtol(end_char,&end_char,2);
  d4 = strtol(end_char,NULL,0);
  fprintf(stdout, "The converted values are: %ld, %ld, %ld and %ld.\n", d1, d2, d3, d4);
 
  return 0;
}

The output from running this program:

$ ./strtol 
Basic string 8887
The converted values are: 1234, 439041102, -170 and 3735928559.

As you can see from the example there are two ways to utilize the strtol function. The first is to simply convert a known good string with a known quantity. The second usage is to take advantage of the endptr knowing that the string to be parsed contains multiple values for conversion and thus specify the endptr rather than using NULL.

Keep in mind, I could check the result of each call to strtol because if an error occurred LONG_MIN or LONG_MAX is returned and errno is set. There is a handy program from the manual pages that checks the results of strtol. I will include it here for completeness.

#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <errno.h>
 
int main(int argc, char *argv[])
{
  int base;
  char *endptr, *str;
  long val;
 
  if (argc < 2) {
    fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
    exit(EXIT_FAILURE);
  }
 
  str = argv[1];
  base = (argc > 2) ? atoi(argv[2]) : 10;
 
  errno = 0;    /* To distinguish success/failure after call */
  val = strtol(str, &endptr, base);
 
  /* Check for various possible errors */
  if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
      || (errno != 0 && val == 0)) {
    perror("strtol");
    exit(EXIT_FAILURE);
  }
 
  if(endptr == str) {
    fprintf(stderr, "No digits were found\n");
    exit(EXIT_FAILURE);
  }
 
  /* If we got here, strtol() successfully parsed a number */
  printf("strtol() returned %ld\n", val);
 
  if (*endptr != '\0')        /* Not necessarily an error... */
    printf("Further characters after number: %s\n", endptr);
 
  exit(EXIT_SUCCESS);
}

While the above may seem overkill, you could potentially make this a wrapper function for a strtol converter, and thus all errors could be caught and success otherwise. There you have it, a few examples of using strtol and a few of the reasons why it is recommended to use this over atoi.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *