C

《Linux 编程实践教程》- 1

January 2, 2018
Linux, C

2018年恢复写博客的第一篇博客。 「·最近在看书,主要是Linux相关的书,尽管即将要进行NLP的研究生阶段,但是回首自己的本科计算机编程经历其实非常浅薄。这两年的积淀在常用算法和数据结构上有一些,在一些基础理论上有一些,但是距离成为一个程序员还有很大的距离。综合各种因素,我选择将Linux学习更透彻作为程序员的落脚点。这是我作为程序员的自我修养。·」 关于这本书 # 这是一本Linux的基础教材,2004翻译过来的。但是国内貌似很少用,作为了课外读物。 这本书的落脚点是编程实践。其中贯穿着Linux的一些原理和使用,以及编程思维。 包括:用户,文件系统,连接,事件驱动,进程通信,多线程,服务,协议等。以Linux的一些已经实现的功能为基础,进行讲解,再实现。 会涉及很多的编程细节的东西,这是上课不会讲到的。都非常的有意思。做到“知其然,知其所以然”。 本书的风格和套路 # 此书适合初学者,但是任何初学者的书都不是完全适合初学者, 有很多概念和细节都需要读者有些了解才能更好读懂。 我在读本书之前的一天读了一部分《Linux系统编程》。这是一个偏底层概念和细节的书,主要在文件系统,I/O,进程,内存,信号,时间上去为Linux系统编程打细节基础,看起来没那么有趣,因为细节太多,但是确实把文件和I/O的概念给我打通了。 有了这些基础再看本书的第一章,并实现其中的more实例就省力很多。此前一个月左右我看过这一章,但是在写代码的时候还是非常不能理解一些细节。 书中会给出全部的实现,但是并不是完整功能的实现,是一部分功能的完整实现。并将剩下的一些功能的实现作为扩展的作业。 在给出实现的时候,会讲相关的基础知识。 比如在第二章讲Who命令的时候,会先告诉你man命令怎么用,以及文档各个部分是什么,怎么去看相关条目,从man手册的那些部分获得什么信息等。 第一章:more命令的实现 # more命令比较简单的功能就是把文件的内容投射到终端上,并且可以向下翻页或翻行。要能从文件中读取也可以从管道中读取内容。 在Linux一切皆文件的设计理念下,要知道各种I/O都可以作为文件来使用,也就是可以用打开文件的方式来打开。无论是文件、管道、设备(键盘)、重定向数据,都可以作为文件来打开读取。 那么实现这样的功能就没有那么困难了。 整体逻辑就是: 打开文件 读取一定的行数 提示翻页或下一行,接受键盘动作 作出反应,重复。 代码中用到了终端设置接口termios.h,让用户输入的操作不被显示,不用回车,直接进入程序。 用到了与终端用文件交互的方式tty。 Code # #include <bits/stdc++.h> #include <unistd.h> #include <termios.h> using namespace std; const int PAGELEN = 24; const int LINELEN = 512; int see_more(FILE * cmd){ int c; printf("\033[7m more? \033[m"); // 白色底色 while( (c = getc(cmd)) != EOF ){ if( c == 'q' ){ return 0; } else if( c == ' ' ) return PAGELEN; else if(c == '\n'){ return 1; } } return 0; } void do_more( FILE * fp ){ char line[LINELEN]; int num_of_lines = 0; FILE * fp_tty = fopen("/dev/tty", "r"); // 一切皆文件,这个文件标志就是与终端交互。 struct termios initial_settings, new_settings; tcgetattr(fileno(fp_tty), &initial_settings); new_settings = initial_settings; // clflag 局部模式,只在本程序中有效。 new_settings. ...

C 函数指针

August 17, 2017
C

C语言有了函数指针以后,就算是完整了,构建了这个世界。 先来看三个例子: A) char * (*fun1)(char * p1,char * p2); B) char * *fun2(char * p1,char * p2); C) char * fun3(char * p1,char * p2); 最后一个很好理解,fun3是函数名,函数返回一个char*。 中间个是返回一个二级指针,本质与最后一个没有什么区别。 在第一个中,其实就是函数指针了,fun1是个函数指针,这个函数返回一个char*。 函数指针其归根结底是一个指针,所以他是可以赋值的。如下的一个函数指针: int (*p)(int a, int b) = NULL;//初始化为 NULL 如果我们要给 p 赋值的话,我们就应该定义一个返回值类型为 int ,两个参数为 int 的函数: int add(int a, int b) { return a + b; } p = add;//给函数指针赋值 经过上面的赋值,我们就可以使用 p 来代表函数: p(5, 6);//等价于 add(5, 6); printf("%d\n", p(5, b)); 当然这并不是主要的用法,最主要的用法是用作回调函数。 ...

Redis 深度学习(1)

August 8, 2017
Redis, C, Nosql

如果人生没有看过一个数据库的源码,那与咸鱼有什么区别。 准确的说,我所会写的代码都是从别人那里看来的。但是我所会写的代码就那么点儿,实在不怎么拿得出手。刚好遇到这个源码只有2万多行的纯C语言的数据库项目,怎么都得读读,否则不敢说自己会写代码。 Redis 简介 # 在之前有一篇关于redis的简介和安装的文章,所以就不从宏观上介绍了。 与memcached相比有下面这几个特点: Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。 Redis支持数据的备份,即master-slave模式的数据备份。 Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。 Redis可以实现主从复制,实现故障恢复。 Redis的Sharding技术: 很容易将数据分布到多个Redis实例中 GitHub地址 Redis是单线程的,运行在CPU的一个核上。所以在线程的思路上整个程序是很清晰的。我主要从代码中学习一些网络编程的方法,C语言数据结构的写法,内存操作。 在redis4.0.1中一共有600多个文件,包含了C文件、bash脚本、Lua脚本、tcl脚本,额,,还有一些没见过的东西。太菜了,连文件后缀都没见过。 但是这些并不都是redis的代码,在src/文件夹中可以看到只有120多个c文件,这些才是核心。600多个是包含了一些测试文件和单元测试等等。 Redis的数据结构 # redis对外提供的数据结构在上一篇中也都介绍过,这里带着介绍一下其内部实现的方式。