我该如何在不包含"unistd.h"的情况下使用read()和write()函数?

4

我的程序中使用了read()和write()系统调用,但没有在程序中包含"unistd.h"头文件。但是程序仍然可以正常工作并给出预期的结果。

运行程序后,我想阅读read()和write()的man手册。

在read()和write()的man 2页面的SYNOPSIS部分中提到,我需要包含unistd.h头文件才能使用read()或write()。

SYNOPSIS
   #include <unistd.h>

   ssize_t read(int fd, void *buf, size_t count);


SYNOPSIS
   #include <unistd.h>

   ssize_t write(int fd, const void *buf, size_t count);

我很惊讶为什么我的程序没有包含unistd.h头文件却能够正常工作呢?

以下是我的程序。它是一个使用read()和write()系统调用将源文件内容复制到目标文件的程序。

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

int main()
{
    /* Declaring the buffer. */
    /* Data read by read() will be stored in this buffer. */
    /* Later when write() is used, write() will take the contents of this buffer and write to the file.*/

    char buffer[512];

    /* Decalring strings to store the source file and target file names. */

    char source[128], target[128];

    /* Declaring integer variables in which integer returned by open() will be stored. */
    /* Note that this program will open a source file, and a target file. So, 2 integers will be needed. */

    int inhandle, outhandle;

    /* Declaring integer variable which will specify how much bytes to read or write.*/

    int bytes;

    /* Taking source filename from keyboard.*/

    printf("\nSource File name: ");
    scanf("%s",source);

    /* Open the source file using open().*/

    inhandle = open(source, O_RDONLY);

    /* If there is error while opening source file.*/

    if (inhandle == -1)
    {
            perror("Error opening source file.\n");
            exit(1);
    }

    /* Taking target filename from keyboard.*/

    printf("\nTarget File name: ");
    scanf("%s",target);

    /* Open the target file using open().*/

    outhandle = open(target, O_CREAT | O_WRONLY, 0660);

    /* If there is error while opening target file.*/

    if (outhandle == -1)
    {
            perror("Error opening target file.\n");
            close(inhandle);
            exit(2);
    }

     /* Below code does following:
       1. First reads (at most) 512 bytes from source file
       2. Then copies them to buffer
       3. If bytes read is greater than 0, write the content stored in buffer to target file.
    */

    while((bytes = read(inhandle, buffer, 512)) > 0)
    {
                    write(outhandle, buffer, bytes);
    }

    /* Close both source and target files. */
    close(inhandle);
    close(outhandle);

    return 0;
}

2
所有警告都启用了,并选择了现代标准吗?-Wall -Wextra -pedantic -std=c11 - Deduplicator
@Deduplicator,我该如何使用-Wall等?它们是编译器开关吗?例如:gcc -Wall hello.c? - sps
1
是的,它们是有效的。尝试使用它们,不要忽略警告。 - Deduplicator
@Deduplicator 哦,我明白了!我使用了-Wall,gcc对read()、write()和(额外的奖励!)close()进行了警告,因为它们没有被声明。我会尝试阅读一下你提到的那些gcc开关到底是做什么的。非常感谢。 - sps
1个回答

0

你的程序之所以能够工作,是因为隐式函数声明,read()write()都返回ssize_t,编译器在隐式声明函数时假定返回类型为int,所以它可能会像你所知道的那样工作。

如果你启用了警告编译选项,那么编译器会警告你这个问题,使用gcc

gcc -Wall -Wextra -Werror

如果发现未显式声明的函数(即没有原型的函数),编译将停止。


是的,你说得对。我使用了-Wall开关,gcc警告了read()、write()和close()的隐式声明。我在man页面中看到,即使close()也需要unistd.h。接下来我想知道IMPLICIT DECLARATION是什么意思,现在我看到你已经在上面解释过了。非常感谢。 - sps
明白了。你的意思是我可以自己声明原型,对吧?不过我有一个问题。虽然原型中说第二个参数应该是 void * 类型,但是 char * 怎么使用呢?我传递的第二个参数是 char * 而不是 void *。同样地,虽然 read 返回 size_t 数据类型,但我将其作为 int 使用它仍然有效... - sps
首先:在C语言中,void *可以转换为任何指针类型而无需进行强制转换,这就是为什么例如malloc()不需要进行强制转换的原因。其次:它不返回size_t,而是返回ssize_t,因为如果出现错误,则会返回-1,如果值不足以使int溢出,则您将不会观察到问题,并且有时ssize_t实际上是int,例如在带有glibc的32位机器上,因此在这种情况下甚至不危险,但最好当然使用ssize_t - Iharob Al Asimi
@iharob:是的,你可以自己声明函数,但没有好的理由这样做。只需要#include正确的头文件,让实现为您声明即可。否则,在您自己的声明中出现拼写错误可能会导致程序静默失败。 - Keith Thompson
@KeithThompson 我并不是说有什么理由,我只是试图让OP明白函数原型是必要的,并且它们在这些头文件中。如果需要这些头文件,一些函数中使用的常量和宏也会在头文件中声明,因此省略包含这些头文件不是一个好主意。 - Iharob Al Asimi
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接