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\$