Reputation: 38
A customer text based protocol is used and it allows to set int32 values for some specific parameters by sending them e.g. from PC to a 32bit µC. I need to check if the received parameter is in range [INT_MIN, INT_MAX]. I need to generate a failure if the number is outside of this range. Simply casting to int and compare that with [INT_MIN, INT_MAX] would fail.
My current idea is:
1. casting the string to number,
2. casting the number to string,
3. compare the received and casted string from 2. ,
If both equal the number in the string should be a valid int32 value.
Are there any other suggetions or ideas? Thx
Upvotes: 0
Views: 1062
Reputation: 153602
How to test a string which is a number for
>INT_MAX
or<INT_MIN
...check if the received parameter is in range [INT_MIN, INT_MAX]
"casting the string to number," and "casting the number to string," will not work as an int
test. Code needs to convert.
long int strtol(const char *nptr, char **endptr, int base)
readily does this. @PSkocik
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
bool test_int(const char *s, int *int_result) {
char *endptr; // Location where conversion stopped
errno = 0; // Need to clear, to test for overflow later
long n = strtol(s, &endptr, 0);
if (errno == ERANGE) {
return false; // Outside long range
}
// In case int is narrower than long
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (n < INT_MIN || n > INT_MAX) {
return false; // Outside int range
}
#endif
if (s == endptr) {
return false; // No conversion
}
// Perhaps allow trailing white-space?
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (*endptr != '\0') {
return false; // Extra junk at the end
}
*int_result = (int) n;
return true;
}
As part of a protocol parser, with various ranged integers, consider a general purpose signed test:
bool test_integer(const char *s, intmax_t *integer, intmax_t mn, intmax_t mx) {
char *endptr;
errno = 0;
*integer = strtoimax(s, &endptr, 0);
if (errno == ERANGE || *integer < mn || *integer > mx) {
*integer = (*integer < mn) ? mn : mx;
errno == ERANGE;
return false; // Outside intmax_t range
}
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (s == endptr || *endptr != '\0') {
return false; // No conversion or junk at end
}
return true;
}
// Sample usage for int
intmax_t im;
if (test_integer(s, &im, INT_MIN, INT_MAX)) {
int i = (int) im;
...
Upvotes: 2
Reputation: 34636
For a fixed number of compile-time numbers this check can be done efficiently directly on the string. More so, given that you can directly tell by the first character whether or not it is negative or not.
After you branch into checking for MAX_INT or MIN_INT, two numbers you can convert to a string cmp
either at design time or once at runtime, you can easily do the following:
cmp
->failYes, this adds an additional loop and n+1 branches in the worst case you if you validate the string in this pass, you can omit all branches in the conversion step, so you will only have to pay one additional branch.
Upvotes: 0