【问题标题】:reading that from serial port in c - array indexing issue从 C 中的串行端口读取它 - 数组索引问题
【发布时间】:2017-11-30 15:45:37
【问题描述】:

我有一些 c 代码从串行端口连续读取到缓冲区,当它读取 100 个字节时,它使用函数log_write() 通过 websocket 将它们写入。 一些数据丢失了,所以我认为我得到了未定义的行为。代码有什么明显的问题吗?

特别是在下面的行中,我应该将 1 添加到 rdlentotal 吗?是否覆盖了上次读取的最后一个字符?

我还应该在读取最后一个字符后终止缓冲区吗?我该怎么做?

rdlen = read(fd_joule, &ibuf[rdlentotal], sizeof(ibuf)); rdlentotal += rdlen; /*keep track of total bytes read*/

int rdlen=0, rdlentotal = 0;
char ibuf[1024];

memset(&ibuf[0], 0, sizeof(ibuf)); /*clear the buffer*/

while (1) {

    /*read from serial port*/
    rdlen = read(fd_joule, &ibuf[rdlentotal], sizeof(ibuf));
    rdlentotal += rdlen; /*keep track of total bytes read*/

    if (rdlentotal > 100) { /*when you have 200 bytes write the websocket*/
        log_write("%s", &ibuf); /*write to websocket*/
        memset(&ibuf[0], 0, sizeof(ibuf)); /*clear buffer*/
        rdlentotal = 0; /*rest byte counter */
        rdlen = 0;
    }

    if (rdlen < 0) {
        fprintf(stderr, "rdlen les than 0\r\n");
    }

}

来自 Chux 的更新代码建议:

static void *serial_logging_thread() {

    ssize_t rdlen = 0, rdlentotal = 0;
    char ibuf[1024 + 1];

    memset(&ibuf[0], 0, sizeof(ibuf)); /*clear the buffer*/

    while (1) {

        /*read from serial port write to log file*/
        rdlen = read(fd_joule, &ibuf[rdlentotal], sizeof(ibuf) - 1 - rdlentotal);
        rdlentotal += rdlen;

        if (rdlentotal > 200) { /*when you have 200 bytes write to file and websocket*/

            ibuf[rdlentotal + 1] = '\0'; /*null terminate*/
            log_write("%s", &ibuf); /*write to websocket*/

            memset(&ibuf[0], 0, sizeof(ibuf)); /*clear buffer*/
            rdlentotal = 0; /*rest byte counter */
            rdlen = 0;
        }

        if (rdlen < 0) {
            LOG("error reading serial port, rdlen less than 0\r\n");
        }
    }

}

log_write() 的声明。

int log_write(const char *fmt, ... /* arguments */){

【问题讨论】:

  • read(fd_joule, &amp;ibuf[rdlentotal], sizeof(ibuf)); --> read(fd_joule, &amp;ibuf[rdlentotal], sizeof(ibuf) - rdlentotal);
  • 请告诉我们 - 字节流中可以包含 NUL 吗?如果是这样,你已经崩溃了,正如下面 chux 所暗示的那样。
  • samsung gather:1) 复查What should I do when someone answers my question? 2) 将问题回滚到以前的版本,而不是为您的问题添加答案副本。

标签: c arrays serial-port


【解决方案1】:

代码有什么明显错误吗?

是的,见下文。

特别是在下面的行中,我应该将 1 添加到 rdlentotal 吗?

没有。

是否覆盖了上次读取的最后一个字符?

没有。

...我应该在读取最后一个字符后终止缓冲区吗?

是的,如果buf 被视为字符串。然而,由于输入中可能包含'\0' 字节,因此更健壮的代码会将buf 视为字符数组并将buf 及其长度传递给日志记录函数。另见@Martin James

我将如何做到这一点(null 终止缓冲区)?

参见下面的#2。


代码至少有以下问题:

  1. 缓冲区溢出的可能性。

    // rdlen = read(fd_joule, &ibuf[rdlentotal], sizeof(ibuf));
    rdlen = read(fd_joule, &ibuf[rdlentotal], sizeof(ibuf) - rdlentotal);
    
  2. 假设log_write("%s", &amp;ibuf);printf() 相似,则代码尝试打印ibuf,它可能不是字符串,也不一定是空字符终止。想想如果第一次读取是sizeof(ibuf) 个字符长会发生什么。相反,确保空间并附加一个空字符。

    char ibuf[1024 + 1];  // add 1 here                   - 1 below
    ...
    rdlen = read(fd_joule, &ibuf[rdlentotal], sizeof ibuf - 1 - rdlentotal);
    ...
    ibuf[rdlentotal + rdlen] = '\0';  // Code is certain to have memory for the \0
    ...
    log_write("%s", &ibuf);  // The use of & here is likely not needed.
    
  3. read() 返回 ssize_t,而不是 int。使用该类型并检查错误之前 rdlentotal += rdlen;

    ssize_t rdlen = read(...
    if (rdlen == -1) {
      LOG("error reading serial port, rdlen less than 0\r\n");
      continue;
    }
    rdlentotal += rdlen;
    
  4. 对于数组长度使用size_tint 更健壮

    // int rdlentotal = 0;
    size_t rdlentotal = 0;
    
  5. 次要:注释不反映代码。

    // if (rdlentotal > 100) { /*when you have 200 bytes write the websocket*/
    if (rdlentotal > 100) { /*when you have more than 100 bytes write the websocket*/
    

【讨论】:

    【解决方案2】:

    上面的评论是正确的。进一步说明,您可以通过覆盖 ibuf 和不可预测的行为和可能的崩溃来破坏堆栈。

    【讨论】:

      猜你喜欢
      • 2017-01-23
      • 1970-01-01
      • 2012-03-10
      • 2019-04-11
      • 1970-01-01
      • 2018-02-12
      • 1970-01-01
      • 2015-11-10
      • 1970-01-01
      相关资源
      最近更新 更多