读取不存在的文件

时间:2011-02-19 07:18:54

标签: 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));

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

这怎么可能?什么是节目印刷?

谢谢, 约翰

4 个答案:

答案 0 :(得分:7)

它正在打印垃圾,因为fd总是被设置为-1,传递给read并不是一件好事,因为它除了返回-1之外什么也不做。它会让你的缓冲区保持不变,这意味着当你开始时它会保留你那里的垃圾。

您可以将整个do循环放在类似:

之类的内容中
if (fd == -1) {
    printf ("error here");
} else {
    // do loop here
}

答案 1 :(得分:5)

读取返回-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);
}

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

关于你的计划的另一个注意事项:

while(bytes_read == sizeof(buffer))

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

答案 2 :(得分:1)

在使用之前,您应该检查open返回的文件描述符是否有效。根据{{​​3}},您应该获得有效文件的非否定响应。从无效的描述符中读取可能是您问题的根源。

答案 3 :(得分:0)

成功完成后,open函数将打开文件并返回表示文件描述符的非负整数。否则,返回-1并设置errno以指示错误。所以请在进入循环之前检查fd以执行读取。