容易忘的小知识
64位传参顺序
6个参数及以内时
参数从左到右加入寄存器时:rdi,rsi,rdx,rcx,r8,r9
当参数为7个以上时
前6个与前面一样,但后面的依次从起,当参数对齐7个时,参数从左到右加入寄存器时:rdi,rsi,rdx,rcx,r8,r9。六个以上的内容加入栈中,即和32位组装一样。
函数原型
open(open64)函数
1 | int open(const char *path, int access, int mode); |
参数解释:
path:要打开的文件路径和名称。
access:访问模式,宏定义和含义如下:
– O_RDONLY(1):只读打开;
– O_WRONLY(2):只写打开;
– O_RDWR(4):读写打开;
还可选择以下模式与以上3种基本模式相与:
– O_CREAT(0x0100)创建一个文件并打开;
– O_TRUNC(0x0200)打开一个已存在的文件并将文件长度设置为0,其他属性保持;
– O_EXCL(0x0400)未使用;
– O_APPEND(0x0800)追加打开文件;
– O_TEXT(0x4000)打开文本文件翻译CR-LF控制字符;
– O_BINARY(0x8000)打开二进制字符,不作CR-LF翻译;
mode:该参数仅在access=O_CREAT方式下使用,其取值如下:
– S_IFMT(0xF000):文件类型掩码;
– S_IFDIR(0x4000):目录;
– S_IFIFO(0x1000):FIFO 专用;
– S_IFCHR(0x2000):字符专用;
– S_IFBLK(0x3000):块专用;
– S_IFREG(0x8000):只为0x0000;
– S_IREAD(0x0100):可读;
– S_IWRITE(0x0080):可写;
– S_IEXEC(0x0040):可执行;
fopen函数
函数原型:
1 | **FILE *fopen(char *filename, char *mode);** |
参数解释:
– filename:文件名称。
– mode:打开模式:
r:只读方式打开一个文本文件(该文件必须存在);
r+:可读可写方式打开一个文本文件(该文件必须存在);
w:只写方式打开一个文本文件(若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件);
w+:可读可写方式创建一个文本文件(若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件);
a:追加方式打开一个文本文件(若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留));
a+:可读可写追加方式打开一个文本文件(若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留));
rb:只读方式打开一个二进制文件(使用法则同r);
rb+:可读可写方式打开一个二进制文件(使用法则同r+);
wb:只写方式打开一个二进制文件(使用法则同w);
wb+:可读可写方式生成一个二进制文件(使用法则同w+);
ab:追加方式打开一个二进制文件(使用法则同a);
ab+:可读可写方式追加一个二进制文件(使用法则同a+);
返回参数: 文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。一般而言,打开文件后会作一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。
两者的区别
前者属于低级IO,后者是高级IO。 前者返回一个文件描述符,后者返回一个文件指针。 前者无缓冲,后者有缓冲。 前者与 read, write 等配合使用, 后者与 fread, fwrite等配合使用。 后者是在前者的基础上扩充而来的,在大多数情况下,用后者。
write函数原型
**
1 | ssize_t write(int fd, const void *buf, size_t count); |
调用该函数时,需要有三个参数,下面简单的介绍下这三个参数的含义。
fd:要操作的文件的文件描述符,通过open函数打开文件时获取。
buf:指定写入数据对应的缓冲区,可以将需要的写入的内容存放到buf中,再将其写入文件里。
count:指定写入的字节数,单位是字节。
返回值:如果写操作顺利完成,则会返回写入的字节数;如果返回值为0,则表示未向文件中写入任何字符;如果写入出错,则会返回-1。
一般来说
fd=1时标准输出,fd=文件fd时输出到文件
read函数原型
C语言中,read
函数是用于从文件描述符中读取数据的函数,其原型如下:
1 |
|
read
函数的参数如下:
fd
:文件描述符,指定要读取的文件或套接字的标识符。buf
:指向存储读取数据的缓冲区的指针。count
:要读取的最大字节数。
read
函数的返回值是实际读取的字节数。如果返回值为0,表示已到达文件末尾;如果返回值为-1,表示读取出错。
需要注意的是,read
函数是一个阻塞函数,当没有数据可读时,它会一直等待直到有数据可读或出现错误。如果需要非阻塞读取数据,可以使用select
或poll
等函数进行操作。
一般来说
fd=0时标准输入,fd=文件fd时读取文件
fd描述符
0,1,2 这三个 fd 值已经被赋予特殊含义,分别是标准输入( STDIN_FILENO ),标准输出( STDOUT_FILENO ),标准错误( STDERR_FILENO )
puts函数
1 | int puts(const char *s); |
printf函数
printf 函数原型为
1 | int printf(const char *fmt, ...) |
后面的参数以fmt的内容定
mprotect函数
1 | #include <unistd.h> |
mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。
prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:
1)PROT_READ:表示内存段内的内容可读;
2)PROT_WRITE:表示内存段内的内容可写;
3)PROT_EXEC:表示内存段中的内容可执行;
4)PROT_NONE:表示内存段中的内容根本没法访问。
需要指出的是,锁指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
如果执行成功,则返回0;如果执行失败,则返回-1,并且设置errno变量,说明具体因为什么原因造成调用失败。错误的原因主要有以下几个:
1)EACCES
该内存不能设置为相应权限。这是可能发生的,比如,如果你 mmap(2) 映射一个文件为只读的,接着使用 mprotect() 标志为 PROT_WRITE。
2)EINVAL
start 不是一个有效的指针,指向的不是某个内存页的开头。
3)ENOMEM
内核内部的结构体无法分配。
4)ENOMEM
进程的地址空间在区间 [start, start+len] 范围内是无效,或者有一个或多个内存页没有映射。
如果调用进程内存访问行为侵犯了这些设置的保护属性,内核会为该进程产生 SIGSEGV (Segmentation fault,段错误)信号,并且终止该进程。
Memset
1 | void *memset(void *str, int c, size_t n) |
复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。其返回值是一个指向 str 的指针
Sprintf
1 | int sprintf(char *str, const char *format, ...) |
发送格式化输出到 str 所指向的字符串。
第二第三个参数对应了 printf 的第一第二个参数,只是多了个输出到的位置,以及检查标签个数和参数个数相同。
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。
Strncmp
1 | int strncmp(const char *str1, const char *str2, size_t n) |
把 str1 和 str2 进行比较,最多比较前 n 个字节。
这个比较是通过逐个比较ascii码实现的,遇到ascii码不同直接返回
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
fgets
fgets函数功能为从指定的流中读取数据,每次读取一行。其原型为:
1 | char *fgets(char *str, int n, FILE *stream); |
从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
scanf()
原型:
1 | `int scanf(const char *format, ...);` |