I have written a C function to parse an IP address that should match the regular expression ^\d+.\d+.\d+.\d+
and nothing else. Additionally all bytes are limited to 0-255.
I tried to catch all invalid inputs, but I am unsure if there are any edge cases I missed or if it could be simplified.
The function is intended to be used in an embedded system. Therefore I don't want to use external libraries (or anything in stdio.h
) and code size is most important.
I am not really looking for stylistic advice, but rather a functional review.
// Returns the number of characters parsed or 0 if not successful unsigned int StringToIp(uint8_t addr[4], const char* ipSrc, const size_t ipSrcLen) { char* ipPtr = ipSrc; int16_t current = -1; uint8_t addrIdx = 0; for (int i = 0; i < ipSrcLen, addrIdx < 4; i++) { char c = *ipPtr++; if (c == '.') { if (current == -1) return 0; // 2 consecutive dots or dot at beginning addr[addrIdx++] = current; current = -1; } else { uint8_t digit = c - '0'; if (digit >= 10) { // Invalid character if (addrIdx == 3 && current >= 0) { // Invalid character at the end is treated as the end of the address addr[addrIdx++] = current; ipPtr--; break; } } if (current == -1) { // first digit of current byte current = digit; } else { // further digits current = current * 10 + digit; if (current > 255) return 0; // current byte greater than 255 => invalid } } } if (addrIdx == 3 && current >= 0) { // write last byte (necessary if at end if string) addr[addrIdx++] = current; } if (addrIdx == 4) { // valid IP address return ipPtr - ipSrc; } else { // invalid IP address return 0; } }
I also wrote the inverse function. Here I am quite sure I got all cases, but the divisions are suboptimal, because the microcontroller has no dedicated divider. Which means extra code for the divisions has to be generated and this bloats the code size and reduces the speed (which is somewhat less important to me).
Is there any why to avoid the divisions?
unsigned int IpToString(char ipDst[4*3+3+1], const uint8_t addr[4]) { char* ipPtr = ipDst; for (int i = 0; i < 4; i++) { uint8_t current = addr[i]; uint8_t h = current / 100; current -= h * 100; uint8_t d = current / 10; current -= d * 10; uint8_t o = current; if (h > 0) *ipPtr++ = '0' + h; if (h > 0 || d > 0) *ipPtr++ = '0' + d; *ipPtr++ = '0' + o; if (i < 3) *ipPtr++ = '.'; } *ipPtr = '\0'; return ipPtr - ipBuffer; }
if
statements? Compare with 200, 100, and then a binary search of 10's digits.\$\endgroup\$inet_*
fromarpa/inet.h
, for example in muslinet_aton.c
andinet_ntoa.c
. (Keep in mind to respect musl's license.)\$\endgroup\$StringToIp(..., "2.0004.6.8", ...)
function? (4 digits in a byte)\$\endgroup\$