当前位置:首页 > 公众号精选 > 嵌入式微处理器
[导读]一、沉浸式学习 以学习一门语言为例: 大多数人都持有一种观念,要真正学好一门语言必须得去所学语言当地学习或生活一段时间。 而事实上,大多数人都没有这样的学习条件。 解决问题的方法是: 自行改造环境,为自己创造沉浸式的学习环境。 例如: 看新语言的


一、沉浸式学习

以学习一门语言为例:
大多数人都持有一种观念,要真正学好一门语言必须得去所学语言当地学习或生活一段时间。

而事实上,大多数人都没有这样的学习条件。

解决问题的方法是:
自行改造环境,为自己创造沉浸式的学习环境。

例如:

  • 看新语言的电影;

  • 更改手机、电脑的语言设置;

  • 看新语言的文档和书籍;

  • 用新语言写 todo list;

  • 用新语言来学习自己需要的专业知识;

  • 翻译新语言的文档并分享;

  • 逛所学语言的论坛和网站;

  • 用新语言写代码注释 / commit message / README / issue;

  • ...

对了,我作为英文的爱好者,一直想重启我的英文学习之路,后续想在公众号里记录一些英文相关的知识,请你们不要笑话我~~~


二、字符串函数库:Simple Dynamic Strings

1. 简介

Simple Dynamic Strings (简称 SDS) 是一个 C 语言字符串库,它增强了 C 语言字符串处理的能力。

设计 SDS 原本是为了满足设计者自身日常的 C 编程,后来又被转移到 Redis 中,在 Redis 中被广泛使用并对其进行了修改以适合于高性能操作。现在,它又被从 Redis 中提取出来的,并 fork 为一个独立项目。

只有 1500 行不到的代码,就能做到 3.2K 个 star,牛牛牛~~~

它有什么优点?

  • 使用更简单;

  • 二进制安全;

  • 效率更高;

  • 与 C 字符串函数兼容;

源码链接:

https://github.com/antirez/sds

源码文件:

sds.c
sdsalloc.h
sds.h
testhelp.h

相关 API:

sds sdsnewlen(const void *init, size_t initlen) 
sds sdsempty(void) 
sds sdsnew(const char *init) 
sds sdsdup(const sds s) 
void sdsfree(sds s) 
void sdsupdatelen(sds s) 
void sdsclear(sds s) 
sds sdsMakeRoomFor(sds s, size_t addlen) 
sds sdsRemoveFreeSpace(sds s) 
size_t sdsAllocSize(sds s) 
void *sdsAllocPtr(sds s) 
void sdsIncrLen(sds s, ssize_t incr) 
sds sdsgrowzero(sds s, size_t len) 
sds sdscatlen(sds s, const void *t, size_t len) 
sds sdscat(sds s, const char *t) 
sds sdscatsds(sds s, const sds t) 
sds sdscpylen(sds s, const char *t, size_t len) 
sds sdscpy(sds s, const char *t) 
int sdsll2str(char *s, long long value) 
int sdsull2str(char *s, unsigned long long v) 
sds sdsfromlonglong(long long value) 
sds sdscatvprintf(sds s, const char *fmt, va_list ap) 
sds sdscatprintf(sds s, const char *fmt, ...) 
sds sdscatfmt(sds s, char const *fmt, ...) 
sds sdstrim(sds s, const char *cset) 
void sdsrange(sds s, ssize_t start, ssize_t end) 
void sdstolower(sds s) 
void sdstoupper(sds s) 
int sdscmp(const sds s1, const sds s2) 
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count) 
void sdsfreesplitres(sds *tokens, int count) 
sds sdscatrepr(sds s, const char *p, size_t len) 
int is_hex_digit(char c) 
int hex_digit_to_int(char c) 
sds *sdssplitargs(const char *line, int *argc) 
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) 
sds sdsjoin(char **argv, int argc, char *sep) 
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen)

2. 比较常用的功能

2.1 创建字符串

sdsnew() 和 sdsfree():

#include <stdio.h>
#include "sds.h"
#include "sdsalloc.h"

int main(void)
{
    sds mystr = sdsnew("Hello World!");
    printf("%s\n", mystr);
    sdsfree(mystr);
}

运行效果:

$ gcc -o sdsdemo sds.c sdsdemo.c
$ ./sdsdemo
Hello World!

看到了吗?

printf 直接就可以打印 sds,这就是说 sds 本身就是 C 语言的字符串类型

sds 的定义如下:

typedef char *sds;

也就是说,sds 是能兼容 libc 里字符串处理函数 (例如strcpy, strcat...)的。

当不再使用 sds 字符串时,就算是空串,也要通过 sdsfree 销毁字符串。

2.2 获取字符串长度

sdsnewlen():

int main(void)
{
    char buf[3];
    sds mystring;

    buf[0] = 'A';
    buf[1] = 'B';
    buf[2] = 'C';
    mystring = sdsnewlen(buf,3);
    printf("%s of len %d\n", mystring, (int) sdslen(mystring));
}

运行效果:

$ ./sdsdemo
ABC of len 3

和 strlen() 有 2 点不同

  • 运行时长固定,sds 内部有数据结构保存着字符串的长度;

  • 长度与字符串内是否有 NULL 无关;

2.3 拼接字符串

sdscat():

int main(void)
{
    sds s = sdsempty();
    s = sdscat(s, "Hello ");
    s = sdscat(s, "World!");
    printf("%s\n", s);
}

运行效果:

$ ./sdsdemo
Hello World!

sdscat 接受的参数是以 NULL 结尾的字符串,如果想摆脱这个限制,可以用 sdscatsds()。

sdscatsds():

int main(void)
{
    sds s1 = sdsnew("aaa");
    sds s2 = sdsnew("bbb");
    s1 = sdscatsds(s1,s2);
    sdsfree(s2);
    printf("%s\n", s1);
}

运行效果:

$ ./sdsdemo
aaabbb

2.4 扩展字符串长度

sdsgrowzero():

int main(void)
{
    sds s = sdsnew("Hello");
    s = sdsgrowzero(s,6);
    s[5] = '!'/* We are sure this is safe*/
    printf("%s\n", s);
}

运行效果:

$ ./sdsdemo
Hello!

2.5 格式化字符串

sdscatprintf():

int main(void)
{
    sds s;
    int a = 10, b = 20;
    s = sdsnew("The sum is: ");
    s = sdscatprintf(s,"%d+%d = %d",a,b,a+b);
    printf("%s\n", s);
}

运行效果:

$ ./sdsdemo
The sum is: 10+20 = 30

2.6 截取字符串

sdstrim():去掉指定字符

int main(void)
{
    sds s = sdsnew("         my string\n\n  ");
    sdstrim(s," \n");
    printf("-%s-\n",s);
}

运行效果:

$ ./sdsdemo
-my string-

去掉了空格和换行符。

sdsrange():截取指定范围内的字符串

int main(void)
{
    sds s = sdsnew("Hello World!");
    sdsrange(s,1,4);
    printf("-%s-\n", s);
}

运行效果:

$ ./sdsdemo
-ello-

2.7 字符串分割 (Tokenization)

sdssplitlen() 和 sdsfreesplitres():

int main(void)
{
    sds *tokens;
    int count, j;

    sds line = sdsnew("Hello World!");
    tokens = sdssplitlen(line, sdslen(line)," ",1,&count);

    for (j = 0; j < count; j++)
        printf("%s\n", tokens[j]);
    sdsfreesplitres(tokens,count);
}

sdssplitlen() 第 3和4 个参数指定分割符为空格。

运行效果:

$ ./sdsdemo
Hello
World!

2.8 字符串合并 (String joining)

sdssplitlen() 和 sdsfreesplitres():

int main(void)
{
    char *tokens[3] = {"foo","bar","zap"};
    sds s = sdsjoin(tokens, 3"|");
    printf("%s\n", s);
}

运行效果:

$ ./sdsdemo
foo|bar|zap

还有其他一些功能,用到再研究吧!

3. 简单了解一下内部实现

在 SDSD 中,使用二进制前缀(头部) 来保存字符串相关的信息,该头部存储在 SDS 返回给用户的字符串的实际指针之前:

+--------+-------------------------------+-----------+
| Header | Binary safe C alike string... | Null term |
+--------+-------------------------------+-----------+
         |
         `-> Pointer returned to the user.

这个 Header 在代码中用结构体来描述,该结构体定义大致如下:

struct sdshdr {
    [...]
    int len;
    char buf[];
};
  • len 存储的是字符串长度;

  • buf 指向紧随其后的字符串首地址;

假设你使用的字符串为 "HELLOWORLD",为了提升效率,SDS 可能会提前分配多一些空间,所以实际的内存布局如下:

+------------+------------------------+-----------+---------------\
| len | buf | H E L L O W O R L D \n | Null term |  Free space   \
+------------+------------------------+-----------+---------------\
             |
             `-> Pointer returned to the user.

现在,我们来看一下 SDS 分配字符串的大致步骤:

sds sdsnew(const char *init)
    initlen 
= (init == NULL) ? 0 : strlen(init);
    sdsnewlen(init, initlen);
        int hdrlen = sdsHdrSize(type);      // 确定 Header 的长度
        sh = s_malloc(hdrlen+initlen+1);    // 分配 Header + String + 1 个字节的空间

        s = (char*)sh+hdrlen;       // 保存 C string 的地址
        SDS_HDR_VAR(8,s);           // 定义 struct sdshdr sh
        sh->len = initlen;          // 初始化 struct sdshdr sh

        if (initlen && init)        // 初始化 C string 
            memcpy(s, init, initlen);
        
        s[initlen] = '\0';          // 总是添加一个 NULL
        return s;                   // 返回 C string

其他的 SDS API 是如何实现的,就留给大家自行分析了。

4. 相关参考

-《Linux程序设计》,6,7.1 章节

-《C primer plus》,11,12 章节

-《C 和指针》,9 章节

-《Linux 系统编程》,9 章节

-《C专家编程》,7.5 章节

-《C和C++程序员面试秘笈》,4 章节


-END-


本文授权转载自嵌入式Hacker,作者:吴伟东Jack




推荐阅读



【01】2020年顶级编程语言
【02】国内为什么写不出操作系统和编程语言?
【03】单片机编程技术学习攻略
【04】终于有人讲清楚了!关于编程语言的那些事儿
【05】编程能力的4种境界,你到哪一级了?


免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

嵌入式ARM

扫描二维码,关注更多精彩内容

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭