【问题标题】:C: removing new line/null terminate input stringC:删除新行/空终止输入字符串
【发布时间】:2016-03-23 16:27:26
【问题描述】:

在 C 中,我使用的是串行库中的这种方法:

int serialport_read_until(int fd, char* buf, char until, int buf_max, int timeout)
{
    char b[1];  // read expects an array, so we give it a 1-byte array
    int i=0;
    do { 
        int n = read(fd, b, 1);  // read a char at a time
        if( n==-1) return -1;    // couldn't read
        if( n==0 ) {
            usleep( 1 * 1000 );  // wait 1 msec try again
            timeout--;
            if( timeout==0 ) return -2;
            continue;
        }
#ifdef SERIALPORTDEBUG  
        printf("serialport_read_until: i=%d, n=%d b='%c'\n",i,n,b[0]); // debug
#endif
        buf[i] = b[0]; 
        i++;
    } while( b[0] != until && i < buf_max && timeout>0 );

    buf[i] = 0;  // null terminate the string
    return 0;
}

它要读取的字符串是这样的: "111\r\n"(后面有一个回车+换行)

它正在使用 Arduino 打印出来

serial.print("1");
serial.print("1");
serial.println("1");

使用 serialport_read_until 方法(char until is '\r\n'),我想确保正确读取整个缓冲区。

下面的char* buf到底是什么样子的?

1) 111\r\n

2) 111\r\n\0

3) 111\0

4) 111

在我使用 sscanf 方法将字符串正确转换为整数之前,我需要弄清楚这部分,但我不确定该使用哪个:

sscanf(buf, "%d\r\n", &amp;num);sscanf(buf, "%d", &amp;num);

另外,我应该将倒数第二行:buf[i] = 0; 改为 buf[i-1] = 0; 吗?

【问题讨论】:

  • 嗯,意大利面!谁写了图书馆,某个面食厨师?

标签: c arduino embedded


【解决方案1】:

在我看来你应该期待111\r\n\0。注意条件b[0] != until是在增加i之后检查的,所以当接收到换行符并退出循环时,i指向\n之后的下一个字节。然后b[i]=0 在那里存储一个空字节。

请注意,此代码似乎有一个错误:如果从未接收到 until 字符,则循环将一直运行到 i == buf_max,然后再存储一个字节并使用空终止符。所以总共存储了buf_max+1 个字节,这意味着下面的代码会有缓冲区溢出:

char mybuf[123];
serialport_read_until(fd, buf, 'x', 123, 42);

除非文档说 buf_max 应该比缓冲区的大小小一,否则会违反直觉且容易出错,否则循环终止条件可能应该是 i+1 &lt; buf_max 或类似的东西。

此外,由于最后检查了i,即使有此修复,如果您传入buf_max == 0,代码仍将存储一个字节(但没有修复它将存储两个字节)。所以这是另一个错误。

char b[1]; 声明和随附的评论也有点奇怪。简单地声明char b; 然后将&amp;b 传递给read() 会更惯用。

因此,如果这是您的代码,还有更多工作要做。如果是别人的代码,我会非常小心地使用这个库,如果这个函数是质量的任何迹象。

在末尾执行buf[i-1]=0 可以避免溢出,但也意味着如果没有收到until 字符,则收到的最后一个字节将丢失。如果您曾经使用buf_max == 0 调用该函数,它也会中断。所以这不是你想要的。

如果您使用sscanf,则是否有尾随空格的问题无关紧要; sscanf("%d") 将忽略它。您应该仔细阅读您的图书馆的sscanf 文档。特别是,它处理空白的方式并不总是直观的。

【讨论】:

  • 想再次检查一下:sscanf(buf, "%d", &amp;num); 是否足以满足这种情况(忽略 \r\n)或者sscanf(buf, "%[^\r\n]", &amp;num); 是否也可以执行相同的功能?
  • sscanf(buf, "%d", &amp;num); 可以正常工作。 sscanf(buf, "%d\r\n", &amp;num); 也可以工作,因为 \r\n 是一个空白字符序列,它匹配字符串中任意数量的空白,包括无空白(再次阅读手册)。 sscanf(buf, "%[^\r\n]", &amp;num); 根本不起作用,因为它期望存储一个字符串,而不是一个整数。你最终会得到 num 包含类似 0x313131 的内容,或者如果字符串超过 sizeof(int) 字节,你会覆盖其他内存。
  • 好的,非常感谢您的洞察力!非常感激。 (ps还在学习C)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
相关资源
最近更新 更多