读取不存在的文件

Joh*_*ohn 2 c unix system-calls

我有一个小程序,使用系统调用打印文件的内容 - 读取.

unsigned char buffer[8];
size_t offset=0;
size_t bytes_read;

int i;

int fd = open(argv[1], O_RDONLY);

do{
    bytes_read = read(fd, buffer, sizeof(buffer));
    printf("0x%06x : ", offset);

    for(i=0; i<bytes_read; ++i)
    {
        printf("%c ", buffer[i]);
    }
    printf("\n");
    offset = offset + bytes_read;
}while(bytes_read == sizeof(buffer));
Run Code Online (Sandbox Code Playgroud)

现在,在运行时,我给出了一个不存在的文件名.它打印出一些与环境变量混合的数据和最后的分段错误.

这怎么可能?什么是程序打印?

谢谢,约翰

pax*_*blo 7

它是打印垃圾,因为它fd总是被设置为-1,这不是一件好事,read因为它会反过来除了返回-1之外什么也不做.它会让你的缓冲区不受影响,这意味着当你开始时它会保留你在那里的垃圾.

您可以将整个do循环放在以下内容中:

if (fd == -1) {
    printf ("error here");
} else {
    // do loop here
}
Run Code Online (Sandbox Code Playgroud)


Jim*_*ter 5

read返回-1因为fd无效,你将它存储在bytes_read中,它是size_t类型的无符号,所以你的循环打印(size_t)-1个字符,这是一个非常大的数字,比缓冲区的大小大得多.因此,您打印了大部分地址空间,然后在最终到达终点并访问无效地址时获得段错误.

正如其他人所提到的(没有回答你的实际问题),你应该检查打开错误的结果.例如,

int fd = open(argv[1], O_RDONLY);
if( fd < 0 ){
    fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(errno));
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)

需要注意的是:如果您在调用strerror之前执行另一个系统调用或调用任何可能进行系统调用的例程(例如printf),则必须保存errno,然后将保存的副本传递给strerror.

关于你的计划的另一个说明

while(bytes_read == sizeof(buffer))
Run Code Online (Sandbox Code Playgroud)

这不是一个好的测试,因为读取的回报可能低于您要求的数量.您的循环应该继续,直到读取返回<= 0.