📜  门| GATE-CS-2016(套装1)|问题 4(1)

📅  最后修改于: 2023-12-03 15:28:44.980000             🧑  作者: Mango

门 | GATE-CS-2016(套装1)|问题 4

本题是GATE-CS-2016(套装1)的第4道问题,考查了解Unix系统调用的特性与实现细节,需要注意一些常见的陷阱。

题目描述

下面的程序段在Unix系统上运行。函数printBlocks()会按照相应的顺序打印每个块的字节数。请填写缺失的代码块,使得程序按照期望的方式运行。

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

void printBlocks(const char *fname) {
    struct stat st;
    if ( stat(fname, &st) == -1)
        return;
    
    printf("Blocks: %ld\n", st.st_blocks);
}

int main(int argc, char *argv[]) {
    char *fname = argv[1];
    int fd;
    
    /* Fill in the missing code */
        
    printBlocks(fname);
    
    return 0;
}

例如,如果编译并运行程序,传入一个文件名为/tmp/myfile.txt,则期望输出如下:

$ gcc -o myfile myfile.c && ./myfile /tmp/myfile.txt
Blocks: 16

注意,在Linux中,一个文件的长度被存储为byte数(字节数),而一个块的大小取决于文件系统。

解题思路

本题实际上考查了Unix系统调用中的lseekreadclose等的使用方式,以及文件描述符、进程间通信等底层概念。具体而言,我们需要先调用open打开文件,得到一个文件描述符,然后再调用stat函数读取文件信息(包括st_blocks信息),最后需要调用close函数关闭文件。在其中很容易出现一些常见的陷阱,比如忘记检查文件打开是否成功、文件描述符的控制权转移、文件的权限检查等等。

由于限制篇幅,这里不再赘述这些具体实现细节。感兴趣的读者可以前往Unix编程手册等资源中查看更详细的内容。

参考代码

下面是可能的一个参考代码(仅供参考,略有简化):

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

void printBlocks(const char *fname) {
    struct stat st;
    if ( stat(fname, &st) == -1)
        return;
    
    printf("Blocks: %ld\n", st.st_blocks);
}

int main(int argc, char *argv[]) {
    char *fname = argv[1];
    int fd;

    // 打开文件
    if ( (fd = open(fname, O_RDONLY)) == -1 ) {
        perror("Error opening file");
        return 1;
    }
    
    printBlocks(fname);

    // 关闭文件
    if ( close(fd) == -1 ) {
        perror("Error closing file");
        return 1;
    }
    
    return 0;
}

其中,open函数的第二个参数确定了打开文件的模式(读、写、追加等),常用标志符包括O_RDONLY(只读模式)、O_WRONLY(只写模式)以及O_CREAT(如果文件不存在则创建)等。调用close函数时需要检查返回值是否为-1,因为在关闭文件时可能会出现一些错误,比如文件不是打开状态等。