前言
从明天起 关心粮食和蔬菜
我有一所房子 面朝大海 春暖花开
本文前提条件
1.了解 posix 线程
2.了解 原子操作
3.具备简单C基础,或者 你也敲一遍.
如果上面不太清楚,你可以翻看我以前的博客,或者'百度'搜索.
结论
1.云风前辈的 玩具 cstring 有点坑, 内存管理很随意(也可能时我菜,理解不了他飘逸的写法)
2.对于江湖中成名已久的 高手, 其实 胜在 思路上.
3.前辈3-4h搞完的,重构了1周, 发现 const char* 和 char* 够用了,真的,越简单越针对 , 越好,学习成本越低
对简单开源代码有兴趣可以看看,毕竟开源的不都是好的.这里做的工作就是简单和扩平台,简单可用升级,如果你也对C字符串感兴趣
可以看看,否则没有必要.
正文
到这里扯皮结束了, 最近任务有点多,游戏公司加班太疯狂了,做的越快任务越多.哎. 以前博客可能讲了不少关于cstring 结构设计.
这里就简单扯一点,重构部分. 从整体上讲,细节自己多练习了.
1.跨平台所做的工作
跨平台主要围绕等待函数和原子操作封装,看下面 的
sc_atom.h 文件内容
#ifndef _SC_ATOM #define _SC_ATOM/** 作者 : wz* * 描述 : 简单的原子操作,目前只考虑 VS(CL) 小端机 和 gcc* 推荐用 posix 线程库*/// 如果 是 VS 编译器 #if defined(_MSC_VER)#include//忽略 warning C4047: “==”:“void *”与“LONG”的间接级别不同 #pragma warning(disable:4047) // v 和 a 多 long 这样数据 #define ATOM_FETCH_ADD(v, a) InterlockedExchangeAdd((LONG*)&(v), (LONG)(a))#define ATOM_ADD_FETCH(v, a) InterlockedAdd((LONG*)&(v), (LONG)(a))#define ATOM_SET(v, a) InterlockedExchange((LONG*)&(v), (LONG)(a))#define ATOM_CMP(v, c, a) (c == InterlockedCompareExchange((LONG*)&(v), (LONG)(a), (LONG)c))/*对于 InterlockedCompareExchange(v, c, a) 等价于下面long tmp = v ; v == a ? v = c : ; return tmp;咱么的 ATOM_FETCH_CMP(v, c, a) 等价于下面long tmp = v ; v == c ? v = a : ; return tmp;*/ #define ATOM_FETCH_CMP(v, c, a) InterlockedCompareExchange((LONG*)&(v), (LONG)(a), (LONG)c)#define ATOM_LOCK(v) while(ATOM_SET(v, 1)) Sleep(0)#define ATOM_UNLOCK(v) ATOM_SET(v, 0)//否则 如果是 gcc 编译器 #elif defined(__GNUC__)#include /*type tmp = v ; v += a ; return tmp ;type 可以是 8,16,32,84 的 int/uint*/ #define ATOM_FETCH_ADD(v, a) __sync_fetch_add_add(&(v), (a))/*v += a ; return v;*/ #define ATOM_ADD_FETCH(v, a) __sync_add_and_fetch(&(v), (a))/*type tmp = v ; v = a; return tmp;*/ #define ATOM_SET(v, a) __sync_lock_test_and_set(&(v), (a))/*bool b = v == c; b ? v=a : ; return b;*/ #define ATOM_CMP(v, c, a) __sync_bool_compare_and_swap(&(v), (c), (a))/*type tmp = v ; v == c ? v = a : ; return v;*/ #define ATOM_FETCH_CMP(v, c, a) __sync_val_compare_and_swap(&(v), (c), (a))/*加锁等待,知道 ATOM_SET 返回合适的值_INT_USLEEP 是操作系统等待纳秒数,可以优化,看具体操作系统使用方式int lock;ATOM_LOCK(lock);//to do think ...ATOM_UNLOCK(lock);*/ #define _INT_USLEEP (2) #define ATOM_LOCK(v) while(ATOM_SET(v, 1)) usleep(_INT_USLEEP)/*对ATOM_LOCK 解锁, 当然 直接调用相当于 v = 0;*/ #define ATOM_UNLOCK(v) __sync_lock_release(&(v))#endif /*!_MSC_VER && !__GNUC__ */#endif /*!_SC_ATOM*/
这里就是统一简单包装gcc 和 VS中提供的 gcc操作.
这里需要说明一下, gcc 中 __sync__... 是基于编译器层的 操作. 而 VS中Interlock... 是基于 Windows api的
有很大不同,这里也只是简单揉了一下,能用的相似的部分.例如
//忽略 warning C4047: “==”:“void *”与“LONG”的间接级别不同 #pragma warning(disable:4047) // v 和 a 多 long 这样数据 #define ATOM_FETCH_ADD(v, a) InterlockedExchangeAdd((LONG*)&(v), (LONG)(a))
主要是防止VS 警告和编译器不通过而改的. v类型不知道而 InterlockedExchangeAdd 只接受 LONG参数.
2.本土个人化接口文件定义
主要见sc_string.h 文件
#ifndef _H_SC_STRING #define _H_SC_STRING#include#include #include "sc_atom.h"#define _INT_STRING_PERMANENT (1) //标识 字符串是持久的相当于static #define _INT_STRING_INTERNING (2) //标识 字符串在运行时中,和内存同生死 #define _INT_STRING_ONSTACK (4) //标识 字符串分配在栈上//0 潜在 标识,这个字符串可以被回收,游离态#define _INT_INTERNING (32) //符号表 字符串大小 #define _INT_ONSTACK (128) //栈上内存大小struct cstring_data {char* cstr; //保存字符串的内容uint32_t hash; //字符串hash,如果是栈上的保存大小uint16_t type; //主要看 _INT_STRING_* 宏,默认0表示临时串uint16_t ref; //引用的个数, 在 type == 0时候才有用 };typedef struct _cstring_buffer {struct cstring_data* str; } cstring_buffer[1]; //这个cstring_buffer是一个在栈上分配的的指针类型 typedef struct cstring_data* cstring; //给外部用的字符串类型/** v : 是一个变量名** 构建一个 分配在栈上的字符串.* 对于 cstring_buffer 临时串,都需要用这个 宏声明创建声明,* 之后可以用 CSTRING_CLOSE 关闭和销毁这个变量,防止这个变量变成临时串*/ #define CSTRING_BUFFER(v) char v##_cstring[_INT_ONSTACK] = { '