разбор строки IP-адреса в 4 одиночных байта

Я программирую на MCU с C, и мне нужно разобрать строку с нулевым завершением, содержащую IP-адрес, на 4 одиночных байта. Я сделал пример с С++:

#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;
}

Этот код печатает 192, 168, 0 и 1 каждый байт в новой строке. Теперь мне нужен каждый байт в одном символе, например char byte1, byte2, byte3 и byte4, где byte1 содержит 1, а byte4 содержит 192... или в структуре IP_ADDR и затем возвращает эту структуру, но я не знаю, как это сделать в С. :(


person BETSCH    schedule 09.02.2012    source источник
comment
Этот код не печатает байты со значениями 192...: он печатает символы... 3 символа для 1 9 2...   -  person pmg    schedule 09.02.2012
comment
О... только что понял, что юзер спросил. Глядя на код с couts, я подумал, что он просто хочет их напечатать. Он действительно хочет байты   -  person Lefteris    schedule 09.02.2012
comment
Явное добавление \0 в конец строкового литерала очень странно. Инициализируя char *a = foo\0, вы создаете строковый литерал из 5 символов с двумя нулевыми байтами в конце.   -  person William Pursell    schedule 09.02.2012


Ответы (4)


Вы можете сделать это посимвольно, как и версия С++ в вашем вопросе.

/* 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;
}
person pmg    schedule 09.02.2012
comment
этот тоже работает, тывм! Мне потребовалось некоторое время, пока я не понял, как это делают *= 10 и += *str - '0'! :П - person BETSCH; 13.02.2012
comment
Инициализация (unsigned char value[4] = {0};) важна. Не забывайте об этом. - person pmg; 13.02.2012
comment
Этот код не будет работать с некоторыми некорректными строками: aaaaaaaaa, 999999999, 999.99999.500AABBBCCCDDEE.399 и т. д. - person pavelkolodin; 11.07.2014

Я хотел бы предоставить более строгую версию для разбора адреса ipv4.

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;
    }
}
person puchu    schedule 30.12.2014

Хороший способ сделать это в C — использовать токенизатор строк. В приведенном ниже примере кода байты сохраняются в массиве байтов, а также печатаются с помощью функции printf. Надеюсь, поможет

#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;
}
person Lefteris    schedule 09.02.2012
comment
этот работает, если я прокомментирую = malloc(10);, поэтому останется только char* buff;. Если я не прокомментирую, я получаю сообщение об ошибке, неверное преобразование из void* в char*, tyvm - person BETSCH; 13.02.2012
comment
Это НЕ работает так, как вы думаете. Ошибка возиться с нераспределенными указателями. Если вы получаете эту ошибку, это означает, что вы компилируете код C++, а не код C. Обязательно 1) Либо исправьте флаги компилятора 2) Если это C++, просто измените строку на: char* buff = (char*) malloc(10); - person Lefteris; 13.02.2012
comment
Нет, это не работает так, как ВЫ думаете. Вы выделяете буфер размером 10 байт с помощью malloc. На самой следующей строке вы указываете бафф в другом месте. Выделенный вами 10-байтовый буфер потерян. В C нет сборки мусора. (Возможно, это не имеет значения в этой маленькой программе, но в функции, основанной на ней, вызываемой много раз в программе....) Затем, в конце программы, вы пытаетесь бесплатно -- что??? Вы попадете туда, когда buff == NULL! - person Basya; 04.03.2020

person    schedule
comment
tyvm, работает как шарм :) редактировать: о, подождите, мой pic18 тоже не имеет этой функции :( - person BETSCH; 09.02.2012
comment
Почему вы не видите, какая из функций в заголовке string.h стандартной библиотеки C поддерживается микроконтроллером pic, с которым вы работаете, а затем сообщаете нам? И sscanf, и strtok (perreal и мой ответ соответственно) являются стандартными библиотечными функциями c. Мы должны знать, сколько из них доступно для вас - person Lefteris; 09.02.2012
comment
Есть библиотека: ссылка и извините, я новичок в stackoverflow, подумал, потому что пометил ее тегом pic18 и c18 вы, ребята, знаете библиотеку, но потом я понял, что также пометил ее с помощью C - person BETSCH; 09.02.2012
comment
стр. 131 связанного pdf-файла. Так что мой ответ можно использовать. Вы проверили это? (это 3-й) - person Lefteris; 09.02.2012
comment
Известно, что sscanf работает медленно, а в некоторых реализациях даже содержит ошибки. Вам следует избегать его использования. - person dothebart; 04.03.2019