为什么read()返回错误的字节数?

时间:2018-07-12 15:43:47

标签: c linux gcc

给出应用程序read-data的以下代码,该代码只需将stdin中的数据读取到分配给堆的缓冲区buf中:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

const size_t BUF_SIZE=1048576*256; // Just for testing, don't do this in prod code
const size_t MAX_READ_SIZE=1048576;

int main(int argc, char *argv[])
{
    // Allocate buffer space on the heap
    char *buf=(char *) malloc(BUF_SIZE);

    // Check for malloc failure
    if (buf==NULL)
    {
        fprintf(stderr,"Unable to allocate %zu bytes\n");
        return 1;
    }

    size_t curOffset=0;

    // Read MAX_READ_SIZE (or smaller) blocks until EOF
    // WARNING: Don't do this in actual "live" code, since it can result
    // in a buffer overflow with an input whose size
    // exceeds that of the pre-allocated buffer
    while (ssize_t numRead=read(STDIN_FILENO,buf+curOffset,MAX_READ_SIZE)>0)
    {
        fprintf(stderr,"Bytes read: %zu\n",numRead);
        curOffset+=numRead;
    }

    // Free buffer space
    free(buf);
    fprintf(stderr,"Total bytes read: %zu\n",curOffset);
}

测试:

$ cat | ./read-data
a
Bytes read: 1
b
Bytes read: 1
c
Bytes read: 1
d
Bytes read: 1
Total bytes read: 4

所有换行符和它们的“字节”在哪里?每个输入应该读取两个字节,总共应该读取8个字节。

比较例如:

使用基本的Unix工具进行测试:

$ cat | printf 'Total bytes read: %u\n' "$(wc --bytes)"
a
b
c
d
Total bytes read: 8

更奇怪的是,给定文件four-lines.txt时,我什至有更疯狂的行为:

$ cat four-lines.txt
a
b
c
d
$ wc --bytes four-lines.txt
8 four-lines.txt
$ <four-lines.txt ./read-data
Bytes read: 1
Total bytes read: 1

该错误必须很明显,但是我只能说: WTF?

更新:正如安德鲁指出的那样,该错误是错误地假设该行中的运算符优先级的问题:

    while (ssize_t numRead=read(STDIN_FILENO,buf+curOffset,MAX_READ_SIZE)>0)

是否可以更改行,以便可以将定义放在while条件内?还是必须在while之前定义numRead?

更新2:修复很明显,感谢WhozCraig的回答,使变量定义的范围限于循环的主体:

for (ssize_t numRead=0;
     (numRead=read(STDIN_FILENO,buf+curOffset,MAX_READ_SIZE))>0;
    )
...

1 个答案:

答案 0 :(得分:4)

您没有将任务缩小到足够的范围:

while (ssize_t numRead=read(STDIN_FILENO,buf+curOffset,MAX_READ_SIZE)>0)

将比较结果 分配给numRead,即0或1。

您要分配的是read的结果:

ssize_t numRead;
while ((numRead=read(STDIN_FILENO,buf+curOffset,MAX_READ_SIZE)) > 0)