函数返回指针类型与函数的可重入性

4 篇文章 0 订阅
4 篇文章 0 订阅

在c和c++中,自动变量在堆栈中分配内存。当包含自动变量的函数或代码块退出时,它们所占用的内存便被回收,它们的内容肯定会被下一个所调用的函数覆盖。这一切取决于堆栈中先前的自动变量位于何处,活动函数声明了什么变量,写入了什么内容等。原先自动变量地址的内容可能被立即覆盖,也可能稍后才被覆盖。
在c和c++中,数组作为参数传入函数或作为结果从函数中返回时,都会隐式使用到指针,即实际传递的是该数组首个元素的地址。因此当函数返回一个数组的时候,实际返回的是指向数组元素的指针,并不是一个真正的数组。
因此,当函数将执行结果存储在数组当中返回相应的指针的时候,需要确保这个数组不是一个在该函数的栈上分配的局部变量。不然的话,在函数执行结束以后,该数组的内存空间可能被重写,从而使函数的返回结果变得无效。
避免这样的问题的一个方法是将数组声明为static类型,下面的例子就用到了这种方法,这个函数用于将Internet地址转换为以圆点分割的十进制形式。

char *inet_ntoa(ad)
  struct in_addr ad;
{
  unsigned long int s_ad;
  int a, b, c, d;
  static char addr[20];

  s_ad = ad.s_addr;
  d = s_ad % 256;
  s_ad /= 256;
  c = s_ad % 256;
  s_ad /= 256;
  b = s_ad % 256;
  a = s_ad / 256;
  sprintf(addr, "%d.%d.%d.%d", a, b, c, d);

  return addr;
}

该函数将执行结果保存在名为addr的缓冲区中,如果这个缓冲区没有被声明为static,则在函数返回以后,缓冲区的内容将会无效,返回的addr也就没有实际的作用了。
当然除了使用上面介绍的将数组的类型指定为static,还有其他的方法,可以参考这一篇文章

下面我们将要从可重入性上来讨论上述几种方法。
使用全局变量或静态变量的函数在大多数情况下是不可重入的。也就是说,如果这个函数的一个实例在运行,程序中的其他线程就不能够调用这个函数。更为糟糕的是,在这个例子中,当该函数被再次调用前,函数的执行结果必须要保存到其他地方,否则,这个结果将会被新的结果重写,例如,在下面的代码中,使用到nadd_ntoa函数的地方并不能使用上面的inet_ntoa函数来替换。

(void)fprintf(ftrace, "%s Router Ad"
                  " from %s to %s via %s life=%d\n",
                  act, naddr_ntoa(from), naddr_ntoa(to),
                  ifp ? ifp->int_name : "?",
                  ntohs(p->ad.icmp_ad_life));

为了避免前面提到的问题,naddr_ntos函数对inet_ntoa函数进行了包装,将其执行结果保存在由四个临时缓冲区组成的循环列表当中。

/* convert IP address to a string, but not into a single buffer
 */
char *
naddr_ntoa(naddr a)
{
#define NUM_BUFS 4
    static int bufno;
    static struct {
        char    str[16];        /* xxx.xxx.xxx.xxx\0 */
    } bufs[NUM_BUFS];
    char *s;
    struct in_addr addr;

    addr.s_addr = a;
    s = strcpy(bufs[bufno].str, inet_ntoa(addr));
    bufno = (bufno+1) % NUM_BUFS;
    return s;
#undef NUM_BUFS
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值