C Basics: Validate an Entire Decimal Number with strtol
A conversion that accepts the beginning of a string is not complete validation. Parse a decimal port while deliberately rejecting whitespace, signs, suffixes, overflow, and out-of-range values.
Prepare a scratch directory
Tested on Linux x86-64 with GCC 14.2.0. You need GCC, the C development headers, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. This example uses the C standard library and no external package.
Keep the same terminal open. Stop if setup fails, before saving the source:
start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1Run the example
Save this as strtol-validation-demo.c:
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static bool parse_port(const char *text, long *port) {
if (*text < '0' || *text > '9') {
return false;
}
char *end;
errno = 0;
long parsed = strtol(text, &end, 10);
if (end == text || *end != '\0' || errno == ERANGE ||
parsed < 1 || parsed > 65535) {
return false;
}
*port = parsed;
return true;
}
int main(void) {
const char *inputs[] = {
"8080", "0", "70000", "80x", "", " 80", "+80",
"9999999999999999999999999999999999999999"
};
for (size_t index = 0; index < sizeof inputs / sizeof inputs[0]; ++index) {
long port = 0;
if (parse_port(inputs[index], &port)) {
printf("Accepted: %s -> %ld\n", inputs[index], port);
} else {
printf("Rejected: [%s]\n", inputs[index]);
}
}
return EXIT_SUCCESS;
}Compile and run it. The && prevents running an old executable if compilation fails:
gcc -std=c17 -Wall -Wextra -Werror -pedantic strtol-validation-demo.c -o strtol-validation-demo &&
./strtol-validation-demoObserved output:
Accepted: 8080 -> 8080
Rejected: [0]
Rejected: [70000]
Rejected: [80x]
Rejected: []
Rejected: [ 80]
Rejected: [+80]
Rejected: [9999999999999999999999999999999999999999]Read the result
The first-character check enforces the example’s digits-only policy. strtol uses base 10, returns the stopping position, and reports range overflow through errno. Clear errno before calling it; testing only the numeric result cannot distinguish every failure from a valid value.
Apply it carefully
The caller must supply a non-null, null-terminated string and a writable output pointer. This example starts in the standard C locale and never changes it. Leading zeroes are accepted as decimal. Parsing a port number does not prove that it is available or permitted to bind; those are separate runtime checks.
The library reference describes the relevant behavior.
Clean up
Remove only the source and executable created here, then remove the empty scratch directory:
rm -- strtol-validation-demo.c strtol-validation-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directoryIf the directory is not empty, inspect what remains before removing anything else.
Acknowledgements
This post was created with assistance from AI.