2017-01-09 11 views
2

В настоящее время я пишу FTP-сервер и мне нужно разобрать IP и порт удаленного сервера из входного буфера строки в следующем формате:Linux sscanf функция не заполняет переменную

xxx,xxx,xxx,xxx,yyy,zzz 

где:

  • xxx обозначает IP-адрес в десятичном октета
  • yyy круглая ((номер удаленного порта)/256)
  • zzz это (удаленный номер порта)% 256

Например: 127,0,0,1,123,64 означает ip = 127.0.0.1 и port = 31552.

настоящее время я использую sscanf извлечь следующие поля ввода строкового буфера:

sscanf(str, "%u,%u,%u,%u,%u,%u", ret_ip, &ip[0], &ip[1], &ip[2], &temp1, &temp2) == 6 

где:

  • ул является входной буфер
  • ret_ip имеет тип uint32_t
  • ip's имеют тип uint32_t
  • TEMP1 и temp2 имеют тип unsigned short int

Пример кода:

#include <stdio.h> 
#include <netdb.h> 
int main(int argc, char *argv[]) 
{ 
    uint32_t ip[4]; 
    unsigned short int temp, temp1; 

    if (sscanf("127,0,0,1,142,214", "%u,%u,%u,%u,%u,%u", &ip[0], &ip[1], &ip[2], &ip[3], &temp, &temp1) == 6) 
    { 
     printf("%u : %u", temp, temp1); 
    } 

    return (0); 
} 

Моя проблема заключается в том, что для правильной строки, значение temp1 всегда 0 (ноль), то есть все остальные переменные заполняются в соответствии со строкой, кроме temp1. Буду признателен за любую помощь.

ответ

4

scanf не так прощает формат спецификатора несоответствие как printf есть. Спецификаторы должны точно совпадать или вы вызываете неопределенное поведение.

unsigned short%hu. %u для unsigned int.

Не существует спецификаторов прямого формата для таких типов, как uint32_t. Вам необходимо: use a macro from inttypes.h: "%" SCNu32.

Все вместе:

if (sscanf(str, "%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%hu,%hu", ret_ip, &ip[0], &ip[1], &ip[2], &temp1, &temp2) == 6) 
+0

Спасибо за помощь, то% х спецификатор сделал трюк. – dotSK

-1

Followling мой код, который, кажется, работает и печатать правильные результаты.

char sentence []="127,0,0,1,123,64"; 
    uint16_t ret_ip; 
    uint16_t ip1, ip2, ip3; 
    uint16_t temp1, temp2; 

    sscanf(sentence, "%d,%d,%d,%d,%d,%d", &ret_ip, &ip1, &ip2, &ip3, &temp1, &temp2); 

    printf("%d, %d\n", temp1, temp2); 
+0

'% d' для' int'. Ошибочно использовать его для 'uint16_t'. –

1

Ниже приведены добавлены к этому ответу по сравнению с имеющимися ответами:

  • Извлечение IP-адреса октета в unsigned char, а затем сохранить их как единый IP-адрес размера uint_32 вместо того, чтобы массив от uint_32. См. this post для получения дополнительной информации.
  • Подходит для вывода sscanf.
  • Код сканирования %hu используется для считывания unsigned short, а код сканирования %hhu используется для считывания unsigned char.
  • Проверка процесса преобразования IP-адрес от string к unitt_32 использованию inet_pton и от unitt_32 до string использования inet_ntop. Прочтите this section сетевой книги Beej, если вы хотите узнать больше.

и вот код:

#include <stdio.h> 
#include <stdlib.h> 
#include <arpa/inet.h> 
int main(int argc, char *argv[]){ 
    unsigned char ip_octects[4] = {0, 0, 0, 0}; 
    uint32_t ip = 0; 
    unsigned short r1 = 0, r2 = 0; 
    unsigned char *str_c = "127,0,0,1,142,214"; 

    if(sscanf(str_c, "%hhu,%hhu,%hhu,%hhu,%hu,%hu", &ip_octects[0], 
        &ip_octects[1], &ip_octects[2], &ip_octects[3], &r1, &r2) == 6){ 

     printf("Extracted ip : port: %hhu.%hhu.%hhu.%hhu:%hu:%hu\n", 
       ip_octects[0], ip_octects[1], ip_octects[2], ip_octects[3], r1, r2); 

     ip = ip_octects[0]  | ip_octects[1] << 8 | 
      ip_octects[2] << 16 | ip_octects[3] << 24; 
     printf("unit32_t ip value: %zu\n", ip); 

     /* We're done but lets verify the results using inet_pton() and inet_ntop() */ 
     unsigned char *str_d = "127.0.0.1"; 
     char str[INET_ADDRSTRLEN]; 
     struct sockaddr_in sa; 
     if(inet_pton(AF_INET, str_d, &(sa.sin_addr)) < 1){ 
      perror("error: invalid input for inet_pton"); exit(1); 
     } 
     printf("inet_pton ip value: %zu\n",sa.sin_addr); 
     if(inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN) == NULL){ 
      perror("error: invalid input for inet_ntop"); exit(1); 
     } 
     printf("inet_ntop str value: %s\n", str); 
    } 
    else{ 
     perror("error: invalid input for sscanf"); exit(1); 
    } 
    return (0); 
}