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

2024-01-17 13:32

本文主要是介绍返回内部静态成员 熟练C/C++(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2007年10月12日 01:25:00

看完陈皓的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, 把值又给了static,static的那块内存最终被写入了a的值,这个时候输出,那当然就输出的同一个值了。还有一种错误写法,如下:

Char *tmp1 = inet_ntoa(a);

Char *tmp2 = inet_ntoa(b);

这样也是有问题的,因为 tmp1 和 tmp2 都指向了一块内存,当前的 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 *) ∈
__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;
}

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1821037


这篇关于返回内部静态成员 熟练C/C++(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/616209

相关文章

Java中的内部类和常用类用法解读

《Java中的内部类和常用类用法解读》:本文主要介绍Java中的内部类和常用类用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录内部类和常用类内部类成员内部类静态内部类局部内部类匿名内部类常用类Object类包装类String类StringBuffer和Stri

C++类和对象之初始化列表的使用方式

《C++类和对象之初始化列表的使用方式》:本文主要介绍C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C++初始化列表详解:性能优化与正确实践什么是初始化列表?初始化列表的三大核心作用1. 性能优化:避免不必要的赋值操作2. 强

C++迭代器失效的避坑指南

《C++迭代器失效的避坑指南》在C++中,迭代器(iterator)是一种类似指针的对象,用于遍历STL容器(如vector、list、map等),迭代器失效是指在对容器进行某些操作后... 目录1. 什么是迭代器失效?2. 哪些操作会导致迭代器失效?2.1 vector 的插入操作(push_back,

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

前端下载文件时如何后端返回的文件流一些常见方法

《前端下载文件时如何后端返回的文件流一些常见方法》:本文主要介绍前端下载文件时如何后端返回的文件流一些常见方法,包括使用Blob和URL.createObjectURL创建下载链接,以及处理带有C... 目录1. 使用 Blob 和 URL.createObjectURL 创建下载链接例子:使用 Blob