目录
本次我将从以下思维导图中的三方面来进行总结:
【1】Linux下的C语言
1.sqlite3库的移植
(1)移植于Linux中运行(X86)
移植步骤:
1> 从官网获取源码,将获取到的源码放到Linux下的一个目录文件中;
解压源码,并进入解压后生成的目录文件;
tar xf sqlite-autoconf-3140100.tar.gz //解压源码
在此目录下新建一个目录文件如“work”,以便后续安装。
2> 配置编译选项
./configure --prefix=$PWD/work //配置编译选项为当前绝对路径下的work目录文件
//configure是一个可执行的配置脚本(用来生成Makefile)
//--prefix:指定安装目录(如果不指定此选项,那么默认安装到系统路径)
//此命令在源码解压后生成的目录文件下执行
3> 编译、安装
make
make install
//此命令在源码解压后生成的目录文件下执行
安装成功后,work目录下的install目录会有:头文件(include)以及库文件。
此时我们就可以写一个测试代码去测试是否能正常编译执行了。测试代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sqlite3.h>
int main(int argc, const char *argv[])
{
sqlite3 *db = NULL;
if (argc != 2)
{
printf("usage:%s <db_name>\n", argv[0]);
}
if (sqlite3_open(argv[1], &db) != SQLITE_OK)
{
printf("err\n");
exit(EXIT_FAILURE);
}
sqlite3_close(db);
return 0;
}
gcc编译后发现,提示“找不到头文件”、“未定义”、“找不到库”等错误或警告,所以在编译时需要指定头文件位置:
//gcc 源文件 -I <头文件路径> -L <库路径> -l<库名称>
gcc sqlite.c -I ./include -L ./lib/ -l sqlite3
//此命令建立在 .c源文件放在之前创建的work目录文件 的前提下
4> 配置系统路径
以上步骤已经生成了可执行文件a.out,但当我们执行时又出现了错误:
./a.out: error while loading shared libraries: libsqlite3.so.0: cannot open shared object file: No such file or directory
这是因为运行时所需要的库找不到,Linux在运行时默认的查找目录为/lib
或者/usr/lib
,所以,我们需要把编译出来的库拷贝到上面两个路径中任意一个即可。
拷贝时需要注意:命令中需要增加-d
选项,保持库的软链接属性。
sudo cp libsqlite3.so* /usr/lib -d //libsqlite3.so* 在work目录下的lib目录里
(2)移植于ARM中使用
只需在配置编译选项步骤换成这一步即可:
./configure --host=arm-linux- --prefix=$PWD/work
//--host:指定编译器
2.共用体与结构体
(1)共用体与结构体的区别
共用体:共用体成员内部共用同一块内存区域
结构体:单独分配内存空间
(2)结构体字节对齐原则
首地址对齐(按最大字节对齐)
总大小对齐(按最大字节对齐)
成员对齐(按当前成员类型对齐)
详细解释:结构体字节对齐3原则
(3)代码实例
typedef int BOOL;
union val_t
{
BOOL b_val; //bool类型存储空间
int i_val; //整形值存储空间
float f_val; //浮点值存储空间
};
此例要求:
①定义一个val_t类型的变量a,对a的f_val进行赋值,然后打印f_val成员的值。
②再定义一个val_t类型的变量b,将a的值赋给变量b。
③比较变量a和变量b是否相等。
#include <stdio.h>
#include <string.h>
typedef int BOOL;
union val_t
{
BOOL b_val; //bool类型存储空间
int i_val; //整形值存储空间
float f_val; //浮点值存储空间
};
int main()
{
union val_t a;
a.f_val = 5.2;
printf("a.f_val = %f\n",a.f_val);
union val_t b = a;
printf("b.f_val = %f\n",b.f_val);
if (memcmp(&b,&a,sizeof(union val_t)) == 0) //内存比较
{
printf("a = b\n");
}
else
{
printf("a != b\n");
}
return 0;
}
3.内核链表
(1)Linux内核中的链表
Linux在2.1的内核中就引入了官方链表,其头文件是:
#include <linux/list.h>
关于Linux的内核链表这里有更详细的介绍:linux内核中的链表。
(2)代码实例
"data":
[
{
"key": 1,
"type": 2,
"val": "10"
},
{
"key": 2,
"type": 1,
"val": "0"
},
{
"key": 3,
"type": 3,
"val": "22.5"
}
]
本次实例的要求是:
将上面的数据节点信息转换为链表结构,并遍历输出。要求根据type的值来决定val的类型。type为1代表bool类型,2代表整形,3代表浮点型。无需解析文本,直接赋值形成节点即可。
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "list.h"
union type_val //val类型共用体
{
bool bool_val;
int int_val;
float float_val;
};
struct node_list //节点结构体
{
int key;
int type;
union type_val val;
struct list_head list; //链表
};
int main(int argc, const char *argv[])
{
//定义结构体变量,并初始化节点
struct node_list node[3] = {{1,2},{2,1},{3,3}};
node[0].val.int_val = 10;
node[1].val.bool_val = 0;
node[2].val.float_val = 22.5;
struct list_head head; //定义链表变量
INIT_LIST_HEAD(&head);
list_add(&node[0].list,&head); //加入链表
list_add(&node[1].list,&head);
list_add(&node[2].list,&head);
struct list_head *pos;
struct node_list *tmp;
list_for_each(pos,&head) //遍历输出链表
{
tmp = list_entry(pos,struct node_list,list);
printf("key: %d type: %d ",tmp->key,tmp->type);
if(tmp->type == 1) //根据type不同,输出不同的val
{
printf("val: %d\n",tmp->val.bool_val);
}else if(tmp->type == 2)
{
printf("val: %d\n",tmp->val.int_val);
}else if(tmp->type == 3)
{
printf("val: %.2f\n",tmp->val.float_val);
}
}
return 0;
}
【2】Git
1.Git简介
Git是目前世界上最先进的分布式版本控制系统。 所谓版本控制系统,即记录文件的每一次改动,不用再手动“另存为”一堆的文件。并且Git还可以和别人一起协同编辑文件。
Git详细简介:Git简介。
分布式版本控制系统较集中式版本控制系统有明显的优点:版本提交无需依赖服务器。
分布式:每一台客户端都有完整的版本备份,版本提交无需依赖服务器。只有多人协作时,需使用服务器完成版本库的交换。
集中式:所有的版本库都存在中央服务器,本地备份依赖中央服务器。如果服务器出现问题,或网络不好,则无法完成备份。
2.Git安装
Git安装步骤及安装包:Git的安装(附安装包)。
3.Git使用
1> Git的使用分为三个区域:工作区、版本库以及远程仓库。
工作区:可以理解为当前所要操作的文件夹,就是一个工作区,并且也是在此文件夹下创建版本库。
版本库:就是Git备份的位置,它是一个隐藏的文件夹,目的就是不希望人们去修改它。
远程仓库:就是远程服务器,也是代码及数据的托管平台。比如GitHub、GitLab和码云等。
2> Git操作:创建版本库、提交、还原、回退及前进等。
创建版本库:
新建文件夹,在右键菜单中选择:创建版本库。
注意:不要直接在桌面点击创建版本库,因为本身桌面也是一个文件夹,创建也是生效的。如果把桌面做成版本库,可以把windows文件夹中隐藏项目选项打开,然后把桌面上的隐藏文件夹.git删除即可恢复。
提交:
在已创建版本库的文件夹下右击。
注意:工作区如果没有修改,是无法触发提交动作的。
丢掉(还原):
此动作指:当工作区已修改,但还未进行“提交”动作时,选择放弃刚刚修改的内容。
在已创建版本库的文件夹下右击。
注意:工作区如果没有修改,是无法触发还原动作的。
回退:
先找到版本日志,然后选择某个版本进行回退。
前进:
与回退不同的是,前进需要找到“显示引用记录”,里面才可以进行版本的前进。
【3】JSON
1.JSON简介
Json是一种轻量级的数据交换格式,它共有六种基本数据类型,分别是:
number //相当于C中的int类型(数字)
boolean //相当于C++中的bool型
string //相当于C++中的string类型、C中的char*型(字符串)
null //相当于C中的NULL型
array //相当于C中的数组[]
object //相当于C++中的类、C中的结构体{}
Json遵守非常严格的格式:
//格式
JSON以大括号“{}”起始和结尾
内容以键值对的形式存在,并且所有的健都是字符串
值的类型就是六种基本数据类型
每个键值对以“,”分割,最后一个键值对不加“,”
//例子
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"middle-school": "\"W3C\" Middle School",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
这里有Json更详细的入门教程:Json入门教程。
2.JSON操作
Json的操作分为两种,分别是序列化和反序列化。
序列化:利用程序生成Json字符串的过程。
反序列化:利用程序将已有的Json字符串解析出我们需要的值的过程。
使用cJSON这是一个详解:cJSON使用详解。
3.代码实例
本次实例要求:
①使用cJSON库对下面的JSON文件进行反序列化操作。ver和cloud的节点直接打印,data的数据节点解析后形成链表(使用内核链表)存储(将下面内容存为文件,读取后解析)。
②解析完成后,再重新序列化为json字符串直接打印。
{
"ver": "1.0",
"cloud": {
"password": "12345678",
"mpassword": "12345678"
},
"data": [{
"key": 1,
"type": 2,
"val": "10"
},
{
"key": 2,
"type": 1,
"val": "0"
},
{
"key": 3,
"type": 3,
"val": "22.5"
}
]
}
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cJSON.h"
#include "list.h"
#define BOOL int
union val_t
{
BOOL b_val;
int i_val;
float f_val;
};
struct data
{
int key;
int type;
union val_t val;
struct list_head list;
};
int main(int argc, const char *argv[])
{
/****************** JSON反序列化 ********************/
char buf[310] = {0}; //存放jsonStr内容
char *jsonStr = buf; //指向buf的指针
//1 读取json内容
FILE *fd = fopen("./jsonStr.txt","r"); //打开jsonStr文件
if(fd == NULL)
{
perror("fopen jsonStr.txt err");
return -1;
}
if(fread(buf,sizeof(char),310,fd) < 0) //读取jsonStr文件内容
{
perror("fread jsonStr.txt err");
return -1;
}
//2 创建cJSON对象,并打印ver和cloud内容
cJSON *root = NULL;
cJSON *item = NULL;
printf(" 1.JSON反序列化:\n");
root = cJSON_Parse(jsonStr);
if(!root)
{
printf("Error before:[%s]\n",cJSON_GetErrorPtr());
}else
{
item = cJSON_GetObjectItem(root,"ver"); //打印ver内容
printf("ver:%s\n",cJSON_Print(item));
item = cJSON_GetObjectItem(root,"cloud"); //打印cloud内容
printf("cloud:%s\n",cJSON_Print(item));
}
//3 创建链表,存放data数据
int i,sizeJson;
cJSON *posJson = NULL;
cJSON *dataJson = NULL;
struct list_head head; //链表
INIT_LIST_HEAD(&head);
item = cJSON_GetObjectItem(root,"data"); //计算data数组有多少成员
sizeJson = cJSON_GetArraySize(item);
for(i = 0;i < sizeJson;i++) //循环加入链表中
{
struct data *node = (struct data*)malloc(sizeof(struct data));
item = cJSON_GetObjectItem(root,"data");
dataJson = cJSON_GetArrayItem(item,i); //获取了data数组中的第i组数据
posJson = cJSON_GetObjectItem(dataJson,"key");
node->key = posJson->valueint; //将key的值放到了结构体中
posJson = cJSON_GetObjectItem(dataJson,"type");
node->type = posJson->valueint;
posJson = cJSON_GetObjectItem(dataJson,"val");
switch(node->type) //根据type转换val,然后赋给结构体
{
case 1:node->val.b_val = atoi(posJson->valuestring);break;
case 2:node->val.i_val = atoi(posJson->valuestring);break;
case 3:node->val.f_val = atof(posJson->valuestring);break;
}
list_add(&node->list,&head); //加入链表
}
//4 打印链表中的内容
struct list_head *pos;
struct data *tmp;
list_for_each(pos,&head)
{
tmp = list_entry(pos,struct data,list);
switch(tmp->type)
{
case 1:printf("type:%d val:%d\n",tmp->type,tmp->val.b_val);break;
case 2:printf("type:%d val:%d\n",tmp->type,tmp->val.i_val);break;
case 3:printf("type:%d val:%.2f\n",tmp->type,tmp->val.f_val);break;
}
}
/****************** JSON序列化 **********************/
//5 构建json
cJSON *json_root = cJSON_CreateObject();
cJSON *json_item = cJSON_CreateObject();
cJSON *json_next = cJSON_CreateArray();
cJSON *json_next_item1 = cJSON_CreateObject();
cJSON *json_next_item2 = cJSON_CreateObject();
cJSON *json_next_item3 = cJSON_CreateObject();
//在根节点下添加ver节点
cJSON_AddItemToObject(json_root,"ver",cJSON_CreateString("1.0"));
//在根节点下添加cloud节点
cJSON_AddItemToObject(json_root,"cloud",json_item);
//在cloud节点下添加password和mpassword节点
cJSON_AddItemToObject(json_item,"password",cJSON_CreateString("12345678"));
cJSON_AddItemToObject(json_item,"mpassword",cJSON_CreateString("12345678"));
//在根节点下添加data数组节点
cJSON_AddItemToObject(json_root,"data",json_next);
//在data数组节点下添加一个节点
cJSON_AddItemToObject(json_next,"",json_next_item1);
//在此节点下添加key、type和val节点
cJSON_AddItemToObject(json_next_item1,"key",cJSON_CreateNumber(1));
cJSON_AddItemToObject(json_next_item1,"type",cJSON_CreateNumber(2));
cJSON_AddItemToObject(json_next_item1,"val",cJSON_CreateString("10"));
cJSON_AddItemToObject(json_next,"",json_next_item2);
cJSON_AddItemToObject(json_next_item2,"key",cJSON_CreateNumber(2));
cJSON_AddItemToObject(json_next_item2,"type",cJSON_CreateNumber(1));
cJSON_AddItemToObject(json_next_item2,"val",cJSON_CreateString("0"));
cJSON_AddItemToObject(json_next,"",json_next_item3);
cJSON_AddItemToObject(json_next_item3,"key",cJSON_CreateNumber(3));
cJSON_AddItemToObject(json_next_item3,"type",cJSON_CreateNumber(3));
cJSON_AddItemToObject(json_next_item3,"val",cJSON_CreateString("22.5"));
printf("\n 2.JSON序列化:\n%s\n",cJSON_Print(json_root));
//关闭jsonStr文件
fclose(fd);
return 0;
}