使用宏来减少函数定义,简化函数调用

文件:recode_lock.h

#ifndef ___RECODE_LOCK__
#define ___RECODE_LOCK__

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>


/* 加非阻塞读锁 */
#define read_lock(fd, l_whence, l_start, l_len) \
lock_set(fd, F_SETLK, F_RDLCK, l_whence, l_start, l_len)

/* 加阻塞读锁  w是阻塞的意思 */
#define read_lockw(fd, l_whence, l_start, l_len) \
lock_set(fd, F_SETLKW, F_RDLCK, l_whence, l_start, l_len)

/* 加非阻塞写锁 */
#define write_lock(fd, l_whence, l_start, l_len) \
lock_set(fd, F_SETLK, F_WRLCK, l_whence, l_start, l_len)

/* 加阻塞写锁 w是阻塞的意思 */
#define write_lockw(fd, l_whence, l_start, l_len) \
lock_set(fd, F_SETLKW, F_WRLCK, l_whence, l_start, l_len)

/* 解锁 */
#define unlock(fd, l_whence, l_start, l_len) \
lock_set(fd, F_SETLK, F_UNLCK, l_whence, l_start, l_len)


/* 操作锁的函数 */
static int lock_set(int fd, int l_ifwset, short l_type, short l_whence, off_t l_start, off_t l_len)
{
    int ret = -1;
    struct flock f_lock;

    f_lock.l_type = l_type;
    f_lock.l_whence = l_whence;
    f_lock.l_start = l_start;
    f_lock.l_len = l_len;

    ret = fcntl(fd, l_ifwset, &f_lock);//加锁解锁, f_lock是一个结构体

    return(ret);
}

#endif

文件:helloworld.c

#include <stdio.h>
#include <stdlib.h>
#include "recode_lock.h"

int main(void)
{
    int ret = 0, fd = -1;

    fd = open("./file", O_CREAT|O_RDWR|O_APPEND|O_TRUNC, 0777);
    if(fd < 0)
    {
        perror("open is fail");
        exit(-1);
    }

    while(1)
    {
        //加阻塞读锁,也就是加锁失败,程序会休眠在这里,就像scanf没有数据,也会休眠一样
        // read_lockw(fd, l_whence, l_start, l_len) lock_set(fd, F_SETLKW, F_RDLCK, l_whence, l_start, l_len);
        // 替换宏得到:lock_set(fd, F_SETLKW, F_RDLCK, SEEK_SET, 0, 0);
        read_lockw(fd, SEEK_SET, 0, 0);




        write(fd, "hello ", 6); // 6 是字符的个数
        write(fd, "world\n", 6);

        unlock(fd, SEEK_SET, 0, 0); //解锁
    }
}

这个是我后面讲《Linux系统编程、网络编程》的例子,我们来分析下这些宏,理解这些宏的作用是什么?

分析这些宏:

像这类宏参数很多,密密麻麻,很多同学一看到这种宏就讨厌,但是不用担心,
分析这类比较复杂的宏定义时是有办法的,办法就是进行宏的替换操作,找到本源后自然就能理解了

当然还有一个办法,那就是查看预编译后的替换结果,不过这样还不如层层替换后分析本源来的更直观

分析的结果总结:

所有带参宏的宏体都指向同一个函数lock_set,通过不同的带参宏去调用lock_set函数,就实现了不同的功能,

为什么要费劲的写这些个复杂的带参宏?

通过前面的介绍我们知道,这个程序的作用是实现对文件的加锁和解锁,可以实现的操作有

  1. 加非阻塞读锁
  2. 加阻塞读锁
  3. 加非阻塞写锁
  4. 加阻塞写锁
  5. 解锁

其实最终是调用fcntl函数来加锁、解锁的,不过为了调用更方便,我们需要进行进一步的函数封装,
其中最笨的方式是定义六个函数,分别是想上述功能

但是最后发现一个现象,那就是所有函数想要做的事情都是一样的,都是去设置文件锁的属性,
每个函数的代码内容几乎一模一样,函数功能的不同仅仅只是靠参数值的不同来体现的

像这种情况,我们定义6个函数来实现,代码其实并不简洁,而且定义这些函数还很花费时间,
此时我们就可以使用带参宏来实现,不仅减少了函数的定义,而且还简化了参数

能够写死的参数就直接在宏体中写死,调用带参宏时,只填写必须要写的参数