在linux中定义了许多错误码,比如:-ENOMEM, -EINTR等错误码。而这些错误码从本质上来说都是一些负整数而已。

    然而在实际的代码过程中,有的函数的返回值是指针类型的,有的是整数类型的。

    比如下面这个函数:

    struct kfifo * kfifo_init()

    {

        struct kfifo *kfifo;

        kfifo = kmalloc(sizeof(struct kfifo), GFP_KERNEL);

        if( !kfifo )

           return -ENOMEM ;

    }

    这个函数要求的返回值是 struct kfifo * 指针类型的。而 return -ENOMEM 返回的确实整数类型的,所以在使用的过程中会发生类型冲突。


    那么内核是如何解决以上的这种问题。最终实现,无论函数的返回值是指针类型还是整数类型,都可以使用内核中定义的错误码。

    内核通过以下几个函数接口来实现的:

    static inline void *ERR_PRT(long error)

    {

        return (void)*error;

    }

    ERR_PRT(long errno)用于将一个错误码转换为一个指针;

    可以将上面的 kfifo_init()更改为:

    struct kfifo * kfifo_init()

    {

       struct kfifo *kfifo;

       kfifo = kmalloc( sizeof(struct kfifo), GFP_KERNEL );

       if( !kfifo )

          return ERR_PTR(-ENOMEM);

    }


    static inline long PTR_ERR( const void *ptr )

    {

         return (long)ptr;

    }

     用于将指针转换为一个错误码;


    static inline long IS_ERR( const void *ptr )

    {

        return IS_ERR_VALUE( (unsigned long)ptr );

    }

     用于判断ptr是否是一个错误码所对应的地址;如果是返回1,否则返回0;

     例如:

           struct kfifo *ret;

           ret = kfifo_init();

           if( IS_ERR(ret) )

                kfree(buffer);

     应为kfifo_init()在出错是返回ERR_PTR(-ENOMEM),所以ret中存放的是(void*)-ENOMEM。

     IS_ERR(ret)就是用来判断ret是否是错误码所对应的地址,如果是的话返回1;


     接口总结:

     PTR 是单词 pointer 的缩写

     ERR 是单词 errno   的缩写

     PTR_ERR 即将指针转换为错误码

     ERR_PTR 即将错误码转换为指针

     IS_ERR  即查看一个指针是否是一个错误码值

     long PTR_ERR(const void *ptr);

     void *ERR_PTR(long errno);

     long IS_ERR(const void *ptr);

     以上这三个接口位于<linux/err.h>之中;