建议9:尽量不要在可重入函数中使用静态(或全局)变量

前面介绍过,静态变量的存储方式与全局变量一样,都是静态存储方式。因此,在使用全局变量、静态变量的函数时,需要考虑重入问题。所谓的可重入函数是指函数可以由多于一个的任务并发使用,而不必担心数据错误。反之,不可重入函数不能由超过一个的任务所共享,除非能够确保函数的互斥性(或者使用信号量,或者在代码的关键部分禁用中断)。

来看一个不可重入函数的示例,代码如下所示:


size_t sum_index( size_t index )
{
    size_t i;
    static size_t sum=0;
    for (i = 1; i <= index; i++)
    {
            sum += i;
    }
    return sum;
}

上面的sum_index函数之所以是不可重入的,就是因为函数中使用了static变量。前面已经阐述过,静态局部变量是在编译时赋初值的,且只赋初值一次,在程序运行时它已有初值。以后在每次调用函数时不再重新赋初值,而是保留上次函数调用结束时的值。所以,这样的函数又被称为带“内部存储器”功能的函数。

函数sum_index的调用示例如下:


int main(void)
{
    printf("%d\n",sum_index(1));
    printf("%d\n",sum_index(2));
    printf("%d\n",sum_index(3));
}

运行结果如图1-44所示。

图1-44 调用sum_index函数的运行结果

由于全局变量与静态变量一样,都是静态存储方式,因此,它同样可以导致不可重入函数,如下面的代码所示:


size_t g_sum = 0;
size_t sum_index( size_t index )
{
    size_t i;
    for (i = 1; i <= index; i++)
    {
            g_sum += i;
    }
    return g_sum;
}

因此,如果需要一个可重入的函数,那么一定要尽量避免使用static变量与全局变量,能不用则尽量不用。当然,有些时候在函数中是必须使用static变量的,比如当某函数的返回值为指针类型时,则必须以static局部变量的地址为返回值,若为auto类型,则返回为错指针。

如果我们需要将上面的函数修改为可重入的函数,其实也很简单,只要将声明sum变量中的static关键字去掉,将变量sum变为一个auto类型的变量,函数即可变为一个可重入的函数。如下面的代码所示:


size_t sum_index( size_t index )
{
    size_t i;
    size_t sum=0;
    for (i = 1; i <= index; i++)
    {
            sum += i;
    }
    return sum;
}