攀升·Uranus


Something Different,Something New
数据加载中……

返回内部静态成员 熟练C/C++(一)

 

        看完陈皓的C/C++返回内部静态成员的陷阱,认识到自己确实对C/C++本身语法研究的不够清楚,所以这些时间就在对基本知识进行回顾,真的还蛮有意思的。

        我在用C/C++函数时,从没有全面考虑过该函数功能,只是知道它能做,基本对函数细节没有了解,就拿下面这个函数做个例子:

        char *inet_ntoa(struct in_addr in);

        struct in_addr {      unsigned long int s_addr; }

 

        看到这个我就能想到该函数是把一个unsigned long type的数转换成一个字符串。其它什么都不想。现在让我们来仔细品读里面的东西。

        我传入一个unsigned long type的数据,它给我传出一个char *,那这个char * 在函数里怎么分配空间的。首先不可能是堆分配,因为如果是那样的话,你用完这个函数后还要释放资源。其次不可能是栈分配,因为那样函数返回后栈也会跟着释放。那还有可能是全局变量,如果这样的话,C/C++中已经有好多全局了。那还有一种是static的可能,static不会随着函数的返回而释放,也就是说,它是一块长期被分配的内存空间,现在在假若我在程序中这样写:

        printf(“%s, %s”, inet_ntoa(a), inet_ntoa(b)); //a, b 是两个不相等的值

        输出会让我大吃一惊,输出结果一样。原因很简单,就是printf先求b,把值给了那个static,然后再求a, 把值又给了staticstatic的那块内存最终被写入了a的值,这个时候输出,那当然就输出的同一个值了。还有一种错误写法,如下:

 

        Char *tmp1 = inet_ntoa(a);

        Char *tmp2 = inet_ntoa(b);

        这样也是有问题的,因为tmp1tmp2都指向了一块内存,当前的static的值就是b的值了。所以总结如下,使用这种函数一定要copy函数返回的值,而不能去保存其内存地址!
附inet_ntoa()源码:
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <bits/libc-lock.h>

/* The interface of this function is completely stupid, it requires a
   static buffer.  We relax this a bit in that we allow at least one
   buffer for each thread.  */


/* This is the key for the thread specific memory.  */
static __libc_key_t key;

/* If nonzero the key allocation failed and we should better use a
   static buffer than fail.  */

static char local_buf[18];
static char *static_buf;                                //静态

/* Destructor for the thread-specific data.  */
static void init (void);
static void free_key_mem (void *mem);


char *
inet_ntoa (struct in_addr in)
{
  __libc_once_define (static, once);
  char *buffer;
  unsigned char *bytes;

  /* If we have not yet initialized the buffer do it now.  */
  __libc_once (once, init);

  if (static_buf != NULL)
    buffer = static_buf;
  else
    {
      /* We don't use the static buffer and so we have a key.  Use it
to get the thread-specific buffer.  */

      buffer = __libc_getspecific (key);
      if (buffer == NULL)
{
  /* No buffer allocated so far.  */
  buffer = malloc (18);
  if (buffer == NULL)
    /* No more memory available.  We use the static buffer.  */
    buffer = local_buf;
  else
    __libc_setspecific (key, buffer);
}
    }

  bytes = (unsigned char *) &in;
  __snprintf (buffer, 18, "%d.%d.%d.%d",
      bytes[0], bytes[1], bytes[2], bytes[3]);

  return buffer;
}


/* Initialize buffer.  */
static void
init (void)
{
  if (__libc_key_create (&key, free_key_mem))
    /* Creating the key failed.  This means something really went
       wrong.  In any case use a static buffer which is better than
       nothing.  */

    static_buf = local_buf;
}

posted on 2007-04-13 16:07 攀升 阅读(1577) 评论(1)  编辑 收藏 引用 所属分类: C/C++

评论

# re: 返回内部静态成员 熟练C/C++(一)   回复  更多评论   

static让我欢喜让我忧。。。
2007-04-13 18:56 | 田德健

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理