热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

阅读redis源码的时候一些c知识

c中的引用之前了解c的时候,简单的看过,但是在阅读c源码的时候会突然出现这种。#一个sds字符串+一个长度,是啥玩意?read(fd,c-querybuf+qblen,readl




c中的引用

之前了解c的时候,简单的看过,但是在阅读c源码的时候会突然出现这种。

#一个sds字符串+一个长度,是啥玩意?
read(fd, c->querybuf+qblen, readlen);

c中有两种引用->和.。

先看下->


  • ->是指向结构体成员运算符

  • ->所指向的是结构体或对象的首地址

  • ->的用处是使用一个指向,以便访问结构体或对象其内成员

看下.


  • .是断点符号,不属于运算符

  • .所指向的是结构体或对象

  • .的用处是使用一个指向以便访问结构体或对象

噢,了解了,querybuf的首地址+对应的长度,也就是从哪块开始


void 关键字,表示没有值

在java中含义很明确,就是修饰方法无返回值,在c中用在不同的地方概念也不同。


表示无返回值

# 表示无返回值
void add(int x,int y);

表示无入参

# 表示无入参
int free(void);

指向指针

一个void* 类型的指针,表示无数据类型的指针,可以指向任意类型的数据

void *memcpy(void *dst, const void *src, size_t n)
int *a;
void *p;
p=a;
# void指针赋值给其他类型的指针,需要强制类型转换
a=(int *)p
# 表示malloc返回的void*指针指向的是int类型
(int *)malloc(1024)

在 ANSI C 标准中,不允许对 void 指针进行一些算术运算


字符串操作


字符复制 memcpy

从源src所指的内存地址的起始位置拷贝n个支付到目标dst所指的内存地址的起始位置。

语法:
void *memcpy(void *dst, const void *src, size_t n)
- dst 用于存储复制内容的目标数组,类型强制转换为 void* 指针
- src 要复制的数据源,类型强制转换为 void* 指针
- n 要复制的直接长度
返回dst的指针
示例:
/**
* @brief sds 拼接
* @param s 当前的sds
* @param t 需要从哪拷贝的指针,大部分都是一个char,部分首地址+长度
* @param len 需要拷贝的长度
* @return sds
*/
sds sdscatlen(sds s, const void *t, size_t len) {
//获取原sds的长度
size_t curlen = sdslen(s);
//空间预分配,如果预留的空间够len,不处理,不够,会调整s的类型
s = sdsMakeRoomFor(s,len);
if (s == NULL) return NULL;
//将t中复制len长度到s首地址+curlen的位置
memcpy(s+curlen, t, len);
sdssetlen(s, curlen+len);
//拼接\0表示字符串的结尾
s[curlen+len] = '\0';
return s;
}
引用示例:
# 指针+偏移量
sdscatlen(c->pending_querybuf, c->querybuf+qblen,nread);
# 字符
sdscatlen(o,"\n",1)

举例说明:

char s1[] ="https://www.5ycode.com/";
char t1[] ="5ycode";
int curlen1 = strlen(s1);
int len1=6;
printf("s1 memcpy before :%s \n",s1);
memcpy(s1, t1, len1);
printf("s1 memcpy after :%s \n",s1);
输出:
s1 memcpy before :https://www.5ycode.com/
s1 memcpy after :5ycode//www.5ycode.com/


字符复制memove

和memcpy差不多。

语法:
void *memmove(void *dst, const void *src, size_t len)
- dst 用于存储复制内容的目标数组,类型强制转换为 void* 指针
- src 要复制的数据源,类型强制转换为 void* 指针
- n 要复制的直接长度

区别:


  • 正常情况下memcpy 和memove的功能一样

  • 当dst和src的内存地址有重合的时候,memove能正确处理,memcpy不保证

  • 由于正确性的保证,memove的效率相对memcpy的效率较低;

在redis中大量的在使用memcpy,因为大部分都是先申请空间,有些地方用到了memove,其中redis中还有一些共用体。


字符填充memset

将b中的前len个字符用c替代。

作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清空操作的最快方法,c和b的内存区域不能重叠,且b中必须有足够空间来存储c

#语法
void *memset(void *b, int c, size_t len)

  • b 指向要填充的内存块

  • c 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式

  • len 要被设置为c的b的字符长度

在redis中的示例

memset(server.cluster->slots_keys_count,0,sizeof(server.cluster->slots_keys_count));

redis中的线程操作

在redis的bio.c中有许多关于锁的操作,在redis6中也是

线程创建相关
pthread_create 创建线程
pthread_attr_init 初始化线程属性
pthread_attr_getstacksize 获取线程栈大小
pthread_attr_setstacksize 设置线程栈大小
线程互斥锁相关
pthread_mutex_init 初始化一个互斥锁
pthread_mutex_lock 获取互斥锁(上锁)
pthread_mutex_trylock 尝试上锁
pthread_mutex_unlock 解除互斥锁
pthread_mutex_destroy 销毁锁
条件变量
pthread_cond_init 初始化条件变量,只有等待这个条件发生线程才继续执行
pthread_cond_wait 等待条件变量的信号或广播
pthread_cond_timedwait 在指定时间内等待条件变量的信号或广播
pthread_cond_signal 唤醒一个条件变量上的阻塞
pthread_cond_broadcast 唤醒所有被阻塞的线程
pthread_cond_destroy 销毁条件变量
设置线程对cancel信号的反应
pthread_setcancelstate
pthread_setcanceltype
两组:
PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ASYNCHRONOUS 表示接收到取消信号后,立即取消(退出)
PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_DEFFERED 表示接收到取消信号后继续运行,直到下一个取消点再退出

语法

/**
* 创建线程。
* @param thread 线程id
* @param attr 属性,一般可设置为NULL
* @param start_routine 执行在子线程的函数
* @param arg 传递到子线程函数的参数
* @return 如果成功返回0,失败返回错误码
*/
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

/**
* 等待线程退出
* 让调用这个方法的线程等待thread退出。如果retval不是NULL,thread的退出状态将存放到retval中。
* @param thread 线程id
* @param retval 获取线程函数返回值,如果不需要可以填NULL
* @return 如果成功返回0,失败返回错误码
*/
int pthread_join(pthread_t thread, void **retval);

/**


  • 初始化一个锁。
  • @param __mutex 锁
  • @param __mutexattr 属性
  • @return 如果成功返回0,失败返回错误码
    */
    int pthread_mutex_init (pthread_mutex_t __mutex,const pthread_mutexattr_t __mutexattr);
    /
  • 销毁一个锁。
  • @param __mutex 锁
  • @return 如果成功返回0,失败返回错误码
    /
    int pthread_mutex_destroy (pthread_mutex_t __mutex);
    /
  • 上锁。
  • @param mutex 锁
  • @return 如果成功返回0,失败返回错误码
    /
    int pthread_mutex_lock(pthread_mutex_t mutex);
    /
  • 尝试上锁。
  • @param mutex 锁
  • @return 如果成功返回0,失败返回错误码
    /
    int pthread_mutex_trylock(pthread_mutex_t mutex);
    /
  • 解锁。
  • @param __mutex 锁
  • @return 如果成功返回0,失败返回错误码
    */
    int pthread_mutex_unlock (pthread_mutex_t *__mutex);

/**
* 使用__cond_attr初始化条件变量,__cond_attr设置为NULL,将使用默认属性初始化条件变量。
* @param __cond 要初始化的条件变量
* @param __cond_attr 属性
* @return 如果成功返回0,失败返回错误码
*/
int pthread_cond_init (pthread_cond_t *__cond,
const pthread_condattr_t *__cond_attr);
/**
* 催毁条件变量。
* @param __cond 要催毁的条件变量
* @return 如果成功返回0,失败返回错误码
*/
int pthread_cond_destroy (pthread_cond_t *__cond);
/**
* 唤醒一个用条件变量__cond等待的线程。
* @param __cond 目标条件变量
* @return 如果成功返回0,失败返回错误码
*/
int pthread_cond_signal (pthread_cond_t *__cond);
/* Wake up all threads waiting for condition variables COND. */
/**
* 唤醒所有用条件变量__cond等待的线程。
* @param __cond 目标条件变量
* @return 如果成功返回0,失败返回错误码
*/
int pthread_cond_broadcast (pthread_cond_t *__cond);
/**
* 等待条件变量__cond的一个信号或者广播。调用该函数之前你应该确保已经用
* __mutex上锁。
* @param __cond 目标条件变量
* @param __mutex 配合__cond的锁
* @return 如果成功返回0,失败返回错误码
*/
int pthread_cond_wait (pthread_cond_t * __cond,pthread_mutex_t * __mutex);
/**
* 在指定时间内等待条件变量__cond的一个信号或者广播,调用该函数之前你应该确保已经用
* __mutex上锁。
* @param __cond 目标条件变量
* @param __mutex 配合__cond的锁
* @param __abstime 绝对时间
* @return
*/
int pthread_cond_timedwait (pthread_cond_t * __cond, pthread_mutex_t * __mutex, const struct timespec * __abstime);
```
一些结构体
```
typedef struct{
int detachstate; //线程的分离状态
int schedpolicy; //线程调度策略
structsched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void* stackaddr; 线程栈的位置
size_t stacksize; 线程栈的大小
}pthread_attr_t;
```
参考文章: 
https://www.runoob.com/cprogramming/c-tutorial.html
https://codbo.cn/blog-12.html
https://blog.csdn.net/chengonghao/article/details/51779279
https://segmentfault.com/q/1010000016389831/a-1020000016390662
**如果觉得本文对你有用,欢迎一键三连哦。**


推荐阅读
  • vue使用
    关键词: ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文讨论了在使用PHP cURL发送POST请求时,请求体在node.js中没有定义的问题。作者尝试了多种解决方案,但仍然无法解决该问题。同时提供了当前PHP代码示例。 ... [详细]
  • 本文介绍了5个基本Linux命令行工具的现代化替代品,包括du、top和ncdu。这些替代品在功能上进行了改进,提高了可用性,并且适用于现代化系统。其中,ncdu是du的替代品,它提供了与du类似的结果,但在一个基于curses的交互式界面中,重点关注占用磁盘空间较多的目录。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 本文介绍了一种求解最小权匹配问题的方法,使用了拆点和KM算法。通过将机器拆成多个点,表示加工的顺序,然后使用KM算法求解最小权匹配,得到最优解。文章给出了具体的代码实现,并提供了一篇题解作为参考。 ... [详细]
  • 本文介绍了如何使用MATLAB调用摄像头进行人脸检测和识别。首先需要安装扩展工具,并下载安装OS Generic Video Interface。然后使用MATLAB的机器视觉工具箱中的VJ算法进行人脸检测,可以直接调用CascadeObjectDetector函数进行检测。同时还介绍了如何调用摄像头进行人脸识别,并对每一帧图像进行识别。最后,给出了一些相关的参考资料和实例。 ... [详细]
author-avatar
mobiledu2502880517
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有