Linux sscanf函数不填充变量

时间:2017-01-09 02:05:30

标签: c linux parsing scanf

我正在编写FTP服务器,我需要以下列格式从输入字符串缓冲区解析远程服务器的ip和端口:

xxx,xxx,xxx,xxx,yyy,zzz

其中:

  • xxx代表十进制的ip地址八位字节
  • yyy是圆形的((远程端口号)/ 256)
  • zzz是(远程端口号)%256

例如:127,0,0,1,123,64表示ip = 127.0.0.1port = 31552

我目前正在使用sscanf从输入字符串缓冲区中提取以下字段:

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

其中:

  • str是输入缓冲区
  • ret_ip的类型为uint32_t
  • ip的类型为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 之外,所有其他变量都根据字符串填充。我将不胜感激任何帮助。

3 个答案:

答案 0 :(得分: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)

答案 1 :(得分:1)

与可用答案相比,以下内容添加到此答案中:

  • 将IP地址八位字节提取为unsigned char,然后将其存储为大小为uint_32的单个IP地址,而不是使用uint_32数组。有关详细信息,请参阅this post
  • 根据sscanf输出进行验证。
  • %hu扫描代码用于阅读unsigned short和。{1}} %hhu扫描代码用于阅读unsigned char
  • 使用inet_pton验证从stringunitt_32以及使用inet_ntopunitt_32string的IP地址转换过程。如果您想了解更多信息,请阅读Beej网络书籍的this section

这是代码:

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

答案 2 :(得分:-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);