【问题标题】:Why doesn't this function return the last full line in a serial file?为什么此函数不返回串行文件中的最后一个完整行?
【发布时间】:2020-07-06 20:19:33
【问题描述】:

我正在编写一个 c 库来帮助读取 linux 上的 arduino 控制器。我的 arduino 代码每 1/3 秒将其每个输入(一个操纵杆和两个按钮)的值以逗号分隔一次写入 /dev/ttyACM0。我的 C 代码应该打印出倒数第二行,也就是最后完成的行,但它只是打印出一个空行。这是我的代码:

char* getLastFullLine() {
    FILE* fd = fopen("/dev/ttyACM0", "r");
    /* max length including newline */
    static const long max_len = 55 + 1;
    /* space for all of that plus a nul terminator */
    char buf[max_len + 1];

    /* now read that many bytes from the end of the file */
    fseek(fd, -max_len, SEEK_END);
    fread(buf, max_len, 1, fd);

    /* don't forget the nul terminator */
    buf[max_len - 1] = '\0';
    char *last_newline;
    /* and find the last newline character (there must be one, right?) */
    last_newline = strrchr(buf, '\n');
    return last_newline;
}
int main() {
    printf("%s \n", getLastFullLine());
}

【问题讨论】:

  • 文件名/dev/ttyACM0代表一个串行终端设备,而不是一个“串行文件”。它不是一个流,应该使用 open()read() 系统调用访问(并正确配置)。 “我的 C 代码应该打印出倒数第二行” -- 试图将程序执行与数据接收同步是愚蠢的。现代 Linux 不会为未打开的串行终端缓冲数据。 IOW 当您打开/打开串行终端 数据已接收(并丢弃)之后,您的程序没有要读取的数据(直到接收到新数据)。

标签: c linux arduino serial-port


【解决方案1】:

有几个问题:不要返回堆栈地址以供重用, 将buf[] 切换为全局或静态; fseek() 返回值被忽略,如果出现错误怎么办? 基于原始参数,fread() 成功可以产生 1 但需要实际读取的字节数; 终止buf[] 假设buf[]fread() 填充 尽管可能的字节数更少, 最好在读取实际字节数后终止; 没有考虑到读取的最后一个字节是 '\n', strrchr() 可以找到。

你的设备支持seek吗?

作为一个非正式的起点,尝试使用足够大的常规文件的这个版本,然后切换到您的设备:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFSIZE 55
char buf[BUFSIZE + 1];


char *
getLastFullLine(void)
{
    char *fname = "/dev/ttyACM0";
    int fd;
    off_t max_len;
    ssize_t nread;
    char *ptr;
    long lsr;

    // tmp for testing
    fname = "infile";

    fd = open(fname, O_RDONLY);
    if (fd < 0) {
        printf("\"%s\" open error\n", fname);
        return (NULL);
    }

    max_len = BUFSIZE;
    lsr = (long) lseek(fd, -max_len, SEEK_END);
    if (lsr < 0) {
        printf("lseek error, %ld\n", lsr);
        return (NULL);
    }
    nread = read(fd, buf, max_len);
    close(fd);
    printf("nread %zd\n", nread);

    ptr = &buf[nread];
    *ptr-- = '\0';
    // ignore last byte if LF
    if (*ptr == '\n')
        *ptr = '\0';
    // printf("buf \"%s\"\n", buf);

    if ((ptr = strrchr(buf, '\n')) == NULL)
        ptr = buf;
    return (ptr);
}

int
main(void)
{
    printf("last line:\n%s\n", getLastFullLine());
    return (0);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    相关资源
    最近更新 更多