I've created this little library to help ease myself (and for others, hopefully) with the pain of having to convert integers to string and vice-versa. It's written in C, and for maximum portability I decided to try and stick to C89 (no booleans yet by that time I believe). I'd like to ask you to give some of your comments and your recommendations, especially on the performance side.
Please note that when I was writing this code, my focus was on readability, self-documenting code and safety. Please also note that my naming convention varies very much from the C naming conventions that I'm sure a lot of you are used to seeing; e.g. abbreviated words instead of the complete words like "recv" for "receive", "u" for "unsigned", etc so if I confuse you with my naming convention then I hope you understand that readability was one of my primary concerns.
For some of the code which I thought some people might find unclear, I've added some comments in hopes of clearing up any confusion.
#include <stdio.h>
#include <stdlib.h>
/*CONSTANTS*/
/* ERROR MESSAGES */
const char *invalidInputError = "convert.c: Unable to convert the input string into a valid number. Offending character has an ASCII value of %d. Valid ASCII values are from 48 to 57 (inclusive) and the null terminator '\0' at the end of the input string.";
const char *outOfBoundariesError = "convert.c: Value was outside of boundaries. Minimum value is 0 and maximum value is 4,294,967,295. Value was %ul";
/* BOUNDARIES */
#define CONVERT_UNSIGNED_INT_MAX 4294967295
#define CONVERT_SIGNED_INT_MIN -2147483648
#define CONVERT_SIGNED_INT_MAX 2147483647
#define CONVERT_UNSIGNED_MIN 0
#define CONVERT_ASCII_ZERO 48
#define CONVERT_ASCII_NINE 57
unsigned int FromStringToUnsignedInteger(char inputString[])
{
unsigned long long boundariesChecker;
unsigned int returnResult; returnResult = 0;
int counter; counter = 0;
// if the ASCII value is not between 48 and 57 inclusive, that's an error, except for '\0', which is the null terminator for C.
while (inputString[counter] != '\0')
{
// check that the input is valid.
if (inputString[counter] >= CONVERT_ASCII_ZERO && inputString[counter] <= CONVERT_ASCII_NINE)
{
// 48 is ASCII for 0, 49 for 1, 50 for 2, ..., 57 for 9.
returnResult = (returnResult * 10) + (inputString[counter] - 48);
boundariesChecker = returnResult;
// check for overflow by getting the max of an unsigned integer (4,294,967,295)
if (boundariesChecker > CONVERT_UNSIGNED_INT_MAX || boundariesChecker < CONVERT_UNSIGNED_MIN)
{
fprintf(stderr, outOfBoundariesError, returnResult);
return 0;
}
counter++;
}
else
{
fprintf(stderr, invalidInputError, inputString[counter]);
return 0;
}
}
return returnResult;
}
int FromStringToInteger(char inputString[])
{
long long boundariesChecker;
int returnResult; returnResult = 0;
int counter;
int isNegative = 0;
// if it's a negative number skip the minus sign and set the flag.
if (inputString[0] == '-')
{
counter = 1;
isNegative = 1;
}
else
{
counter = 0;
isNegative = 0;
}
// if the ASCII value is not between 48 and 57 inclusive, that's an error, except for '\0', which is the null terminator for C.
while (inputString[counter] != '\0')
{
// check that the input is valid.
if (inputString[counter] >= CONVERT_ASCII_ZERO && inputString[counter] <= CONVERT_ASCII_NINE)
{
// 48 is ASCII for 0, 49 for 1, 50 for 2, ..., 57 for 9.
returnResult = (returnResult * 10) + (inputString[counter] - 48);
boundariesChecker = returnResult;
// check for overflow by getting the max of an unsigned integer (4,294,967,295)
if (boundariesChecker > CONVERT_SIGNED_INT_MAX || boundariesChecker < CONVERT_SIGNED_INT_MIN)
{
fprintf(stderr, outOfBoundariesError, returnResult);
return 0;
}
counter++;
}
else
{
fprintf(stderr, invalidInputError, inputString[counter]);
return 0;
}
}
if (isNegative)
{
returnResult = returnResult * -1;
}
return returnResult;
}
char *FromUnsignedIntegerToString(unsigned int inputUnsignedInt) {
// check for out of range
if (inputUnsignedInt > CONVERT_UNSIGNED_INT_MAX || inputUnsignedInt < CONVERT_UNSIGNED_MIN)
{
fprintf(stderr, outOfBoundariesError, inputUnsignedInt);
return NULL;
}
// 10 is the multiplier because there's only 10 chars in the max value of an unsigned int.
char *convertedInputUnsignedInt = malloc(10 * sizeof(char));
sprintf(convertedInputUnsignedInt, "%u", inputUnsignedInt);
return convertedInputUnsignedInt;
}
char *FromIntegerToString(int inputInt) {
// check for out of range
if (inputInt > CONVERT_SIGNED_INT_MAX || inputInt < CONVERT_SIGNED_INT_MIN)
{
fprintf(stderr, outOfBoundariesError, inputInt);
return NULL;
}
// 11 is the multiplier because there's only 11 chars in the max value of an unsigned int, including the negative sign.
char *convertedInputUnsignedInt = malloc(11 * sizeof(char));
sprintf(convertedInputUnsignedInt, "%d", inputInt);
return convertedInputUnsignedInt;
}
sprintf()
\$\endgroup\$