《Linux程序设计》——文件操作之底层函数调用
《Linux程序设计》一书的第三章是讲有关文件操作的函数及其用法的,其中第一节讲的是底层函数调用write,read,open,close,itocl。其中,open函数被定义在头文件fcntl.h中(如果系统不符合POSIX规范的话,有可能在使用时还要包含头文件sys/types.h和sys/stat.h);另外四个函数则被定义在头文件unistd.h中。当然了,这是这本书上所说的内容。
但是我打开这个头文件后,看到的是这个
(unistd.h:/usr/include/linux/unistd.h)
#ifndef _LINUX_UNISTD_H_
#define _LINUX_UNISTD_H_
/*Include machine specific syscall numbers*/
#include <asm/unistd.h>
#endif /* _LINUX_UNISTD_H_ */
就是说,其实write,read,close,iotcl这几个函数是定义在头文件asm/unistd.h中的,可惜我找了一大圈也没有找到。好了,来看看这几个函数吧。
1.write函数:
size_t write(int fildes, const void *buf, size_t nbytes);
Linux下在xterm里使用可以使用 man 2 write来查看write函数的、用法等细节。
write函数有三个参数,第一个参数为int类型的fildes,指的是文件描述符,目前我知道的文件描述符有三个:0,代表标准输入;1,代表标准输出;2代表标准错误。第二个参数是一个无类型的const指针,指向要向指定文件(输出流和错误流也是一个文件)输出的内容。第三个参数则是一个size_t类型的值,表示要从buf中读取的长度。而write函数的返回值则是指实际写入到指定文件中的长度。看下面这个程序:
#include <unistd.h>
#include <stdlib.h>
int main() {
if ((write(1, "Here is some date\n", 18)) != 18)
write(2, "A error has occured on file descriptior 1\n", 42);
exit(0);
}
编译后在终端中运行,运行结果是输出(即将内容写入到标准输出流中)了"Here is some date"。如果稍微改变一下write的实参值,会怎么样呢?
将第一个write函数的第三个参数改为17,运行结果如下:
Here is some dataA error has occured on file descriptior 1
着是因为"Here is some data\n"的长度是18(\n算一个字符),在第三个参数的指小于buf实际长度的时候,write将按照nbytes的指示,只讲buf内的部分内容写入到文件描述符代表的文件中去。那么,当nbytes的值大于buf的实际长度时,会怎么样呢?
将18改为20,在终端中运行的结果为:
Here is some data
A error has occured on file descriptior 1
这说明write在buf读取字符时,会在独到\0后终止读取行为。但是这样以来,又有了一个新的问题,那就是,write函数的返回值难道是由第三个参数来决定的么?事实上,如果将程序改为这个样子:
#include <stdio.h>
int main() {
int nb;
nb = (int)write(1, "Here is some\n", 18);
if (nb != 18)
write(2, "A error has occured on file descriptior 1\n", 42);
printf("\nThe value returned by the function write is %d\n", nb);
exit(0);
}
编译运行后的结果为:
Here is some
A
The value returned by function write is 18
这种结果真是让人百思不得其解……如果说write函数的返回值是由第三个参数决定有些诡异,起码我还可以接受,但是第二行的A是怎么回事?这个A明显是if语句块里的那个write函数的结果。如果nb的值确实是18,那么按理来说,if语句就不会执行,就不会有这个A;如果nb的值不是18,那么按理第二行应该输出:A error has occured on file descriptior 1\n。事实上,当第三个参数的值大于第二个参数字符串的长度时,会出现各种古怪的输出。(好吧,这个地方我纠结了,不过经过这个过程,可以说对write函数有了比较深入的了解,就是现在gdb还不是很熟悉,所以这个问题暂时先放下吧,等把gdb的使用都熟悉了,就仔细地调试一下,找找问题吧,另外那个头文件asm/unistd.h也找一找吧)