parsing ip adress string in 4 single bytes

22,755

Solution 1

You can do it character-by-character, as does the C++ version in your question.

/* ERROR CHECKING MISSING */
#include <ctype.h>
#include <stdio.h>
int main(void) {
    char *str = "192.168.0.1", *str2;
    unsigned char value[4] = {0};
    size_t index = 0;

    str2 = str; /* save the pointer */
    while (*str) {
        if (isdigit((unsigned char)*str)) {
            value[index] *= 10;
            value[index] += *str - '0';
        } else {
            index++;
        }
        str++;
    }
    printf("values in \"%s\": %d %d %d %d\n", str2,
              value[0], value[1], value[2], value[3]);
    return 0;
}

Solution 2

for(int i = 0, r = 0; i < 4; str += r + 1, i++) {
  sscanf(str, "%d%n", &b[i], &r);
}

or

 sscanf(str, "%d.%d.%d.%d", b, b + 1, b + 2, b + 3);

Solution 3

a nice way to do this in C is to use the string tokenizer. In the example code below the bytes are saved in the bytes array and are also printed with the printf function. Hope it helps

#include <string.h>

int main()
{
    char str[] = "192.168.0.1";
    unsigned char bytes[4];
    int i = 0;

    char* buff = malloc(10);
    buff = strtok(str,".");
    while (buff != NULL)
    {
       //if you want to print its value
       printf("%s\n",buff);
       //and also if you want to save each byte
       bytes[i] = (unsigned char)atoi(buff);
       buff = strtok(NULL,".");
       i++;
    }
    free(buff);
    return 0;
}

Solution 4

I'd like to provide more strict version for parsing ipv4 address

typedef struct ipv4_type {
    uint8_t data[4];
} ipv4;

ipv4_error ipv4_parse ( const uint8_t * string, uint8_t string_length, ipv4 * result )
{
    bool at_least_one_symbol = false;
    uint8_t symbol, string_index = 0, result_index = 0;
    uint16_t data = 0;
    while ( string_index < string_length ) {
        symbol = string[string_index];
        if ( isdigit ( symbol ) != 0 ) {
            symbol -= '0';
            data   = data * 10 + symbol;
            if ( data > UINT8_MAX ) {
                // 127.0.0.256
                return ERROR_IPV4_DATA_OVERFLOW;
            }
            at_least_one_symbol = true;
        } else if ( symbol == '.' ) {
            if ( result_index < 3 ) {
                if ( at_least_one_symbol ) {
                    result->data[result_index] = data;
                    data = 0;
                    result_index ++;
                    at_least_one_symbol = false;
                } else {
                    // 127.0..1
                    return ERROR_IPV4_NO_SYMBOL;
                }
            } else {
                // 127.0.0.1.2
                return ERROR_IPV4_INPUT_OVERFLOW;
            }
        } else {
            // 127.*
            return ERROR_IPV4_INVALID_SYMBOL;
        }
        string_index ++;
    }
    if ( result_index == 3 ) {
        if ( at_least_one_symbol ) {
            result->data[result_index] = data;
            return 0;
        } else {
            // 127.0.0.
            return ERROR_IPV4_NOT_ENOUGH_INPUT;
        }
    } else {
        // result_index will be always less than 3
        // 127.0
        return ERROR_IPV4_NOT_ENOUGH_INPUT;
    }
}
Share:
22,755
BETSCH
Author by

BETSCH

Updated on July 09, 2022

Comments

  • BETSCH
    BETSCH almost 2 years

    I'm programming on a MCU with C and I need to parse a null-terminated string which contains an IP address into 4 single bytes. I made an example with C++:

    #include <iostream>
    int main()
    {
        char *str = "192.168.0.1\0";
        while (*str != '\0')
        {
                if (*str == '.')
                {
                        *str++;
                        std::cout << std::endl;
                }
                std::cout << *str;
                *str++;
        }
        std::cout << std::endl;
        return 0;
    }
    

    This code prints 192, 168, 0 and 1 each byte in a new line. Now I need each byte in a single char, like char byte1, byte2, byte3 and byte4 where byte1 contains 1 and byte4 contains 192... or in a struct IP_ADDR and return that struct then, but I dont know how to do it in C. :(