4

I have used syscalls read() and write() in my program WITHOUT including "unistd.h" header file in the program. But still the program works and gives expected results.

After running the program, i thought i will read the man page for read() and write().

In the man 2 page for read() and write(), in the SYNOPSIS section it is mentioned that I need to include unistd.h header file to use read() or 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);

So I am surprised how did my program work although I had not included unistd.h ?

Below is my program. It's a program to copy contents of a source file to target file using read(), and write() syscalls.

#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;
}
sps
  • 2,720
  • 2
  • 19
  • 38
  • 2
    Were all warnings enabled, and a modern standard selected? `-Wall -Wextra -pedantic -std=c11` – Deduplicator Feb 16 '15 at 20:40
  • @Deduplicator, How do I use -Wall , etc ? Are they compier switch which I can use with gcc ? for ex: gcc -Wall hello.c ? – sps Feb 16 '15 at 20:42
  • 1
    Yes, they are. Try them, and don't ignore warnings. – Deduplicator Feb 16 '15 at 20:43
  • @Deduplicator Oh i see !! I used -Wall and gcc gives warning for read(), write(), and (a bonus!) close() for implicit declaration. I will try to read what those gcc switches you mentioned exactly do. Thanks much. – sps Feb 16 '15 at 20:51

1 Answers1

0

Your program worked because of implicit function declaration, read() and write() both return ssize_t and compiler the compiler assumes int when implicitly declaring functions, so it might work as you know.

If you compile your program with warnings enabled, then the compiler would warn you about that, using gcc

gcc -Wall -Wextra -Werror

would stop compilation if it finds implicitly declared functions, i.e. functions without a prototype.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • Ya what you said it right. I used -Wall switch and gcc warned for implicit declaration of read() , write(), AND ALSO close(). I saw in man page that even close() needs unistd.h . Next I was wondering what IMPLICIT DECLARATION means, and now i saw you already told above what it means. Thanks much – sps Feb 16 '15 at 20:54
  • You don't strictly need the includes, you can do this too `ssize_t read(int fd, void *buf, size_t count);` anywhere in the global scope before calling `read()` and it will do what it's supposed to do, in fact that's what will be in the header. – Iharob Al Asimi Feb 16 '15 at 21:14
  • Got you. I can declare the prototype myself you mean right. I have a question in this though. Although the prototye says the second argument should be of void * type, how this works with char * ? Second argument that I have passed is a char * and not a void * . Similary although read returns size_t data type I take it in an int and it still works ... – sps Feb 16 '15 at 21:21
  • **First**: In c `void *` is convertible to any pointer type without the need to cast, that's why casting `malloc()` is not needed for example. **Second**: it does not return `size_t` it's `ssize_t` it's `signed` because on error `-1` is returned, and if the value is not large enough to overflow an `int` then you will not observe a problem, and sometimes `ssize_t` is in fact `int` for example on 32bit machines with `glibc` it is, so in that case it's not even dangerous, but you better use `ssize_t` of course. – Iharob Al Asimi Feb 16 '15 at 21:24
  • Ok, i see that void * is flexible. A bit confused with the size_t part you said, but i can relate a little though. I guess i have write to write some programs so that i can see error / warning / outputs and try to understand. I hope soon. Thanks. – sps Feb 16 '15 at 21:29
  • @iharob: Yes, you *can* declare the functions yourself, but there is no good reason to do so. Just `#include` the correct header(s) and let the implementation declare them for you. Otherwise a typo in your own declaration can quietly cause the program to misbehave. – Keith Thompson Feb 17 '15 at 00:58
  • @KeithThompson I don't say there is a reason, I just tried to make the OP understand that function prototypes where needed and that they where in this headers, and of the headers are needed, the constants used in some functions are declared in the headers and some macros too, so omitting to include the headers is not a good idea. – Iharob Al Asimi Feb 17 '15 at 01:00
  • Your previous comment didn't mention that declaring the functions manually is a bad idea. It's also worth mentioning that C99 dropped the "implicit `int`" rule. – Keith Thompson Feb 17 '15 at 02:14