How to take a argv
and convert it to uint16_t
(?)
argv[i]
may point to a string. The task is then to convert that string into a uint16_t
.
OP's code fails as the below is more like taking the address of the string and converting it to a 16-bit value with potential truncation.
uint16_t PORT;
PORT = argv[2]; // poor code
Insure valid argv[2]
int main(int argc, char *argv[]) {
if (argc <= 2) {
fprintf(stderr, "argv[2] missing.\n");
return EXIT_FAILURE;
}
...
Handle non-numeric input
What should happen in cases like "abc"
, "123abc"
, "-123"
, ""
, " "
, " 123 "
, "123 abc"
, "123456"
, "123456789012345678901234567890"
, "0x123"
, "-0"
, "0.0"
, etc?
The usually goal is to be generous in allowing leading white-space and perhaps trailing WS (even though such WS is uncommon in argv[]
). Complain about values outside the range [0...65535]. Complain about other non-integer numeric, non-white-space characters.
strtoul()
is a good start with its well defined error handling.
atoi()
fails to convert well to a uint16_t
when input is not well formed or when int
is 16-bit.
An attribute of strtoul()
I do not like is that the '-'
is applied after the conversion, so "-1"
is OK input and returns a value of ULONG_MAX
. I would rather detect that as an error. Since the range of long
is always wider than uint16_t
, I recommend strtol()
if code should detect negative values as an error.
Sample
char *endptr;
errno = 0;
long value = strtol(argv[2], &endptr, 0);
if (errno) { // This test not certainly needed here as later test will catch
perror("argv[2] error");
return EXIT_FAILURE;
}
if (argv[2] == endptr) { // No conversion happened
fprintf(stderr, "argv[2] <%s> non-numeric\n", argv[2]);
return EXIT_FAILURE;
}
if (value < 0 || value > UINT16_MAX) {
fprintf(stderr, "argv[2] %ld outside uint16_t range\n", value);
return EXIT_FAILURE;
}
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (*endptr) {
fprintf(stderr, "argv[2] <%s> trailing non-numeric text\n", argv[2]);
return EXIT_FAILURE;
}
PORT = (uint16_t) value; // Cast to quiet conversion warning
printf("argv[2] --> %u success\n", PORT);
return EXIT_SUCCESS;
}
This lengthy code best incorporated as a helper function than replicated for each string to uint16_t
. Yet I suspect OP will get to such functions later.