使用文本编译器Code

[toc]

gcc

gcc是c/c++语言的编译器 只是在编译程序时需要

一般来说 windows使用的mingw的gcc
当然 有很多方法

方法1 安装mingw

随便找了一个,因为下载源在国外 下载速度很慢,所以我挂了个网盘链接 建议是做好科学上网的准备,如果因为网络原因 方法1可能安装成功,可能安装失败,如果安装失败 参考方法3

「setup-x86_64.exe」,点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载,极速在线查看享用。
链接:https://www.aliyundrive.com/s/nSchSQCVzAx

然后下一步安装法直到出现这个界面 像我一样勾选

先选择分类为category

然后点开Devel

接着往下滑 直到找到gcc(可以在搜索框里面输入gcc)

像我一样 先选择对应的版本 然后勾选框框

然后往下执行

当完成安装过后 点击windows菜单 开始搜索 编辑系统环境变量

像这样

进入过后

双击path

点击新建添加新的环境变量 通过浏览找到安装cygwin64的目录 然后把双击下面的bin目录将其作为环境变量

都确认过后 打开cmd 输出如其

gcc: fatal error: no input files
compilation terminated.

就成功了

方法2 使用wsl2 子系统也就是linux

暂时不讲

方法3 将gcc指向dev的gcc(只能说将就)

暂时不讲

code(推荐 本编教程)

考虑到抽筋的网络问题 直接从我的分享下载吧

如果是linux或者Mac 请到官网下载

我的备份

然后开始安装

全部勾选

然后无脑下一步安装法

装好过后打开

111

如我所示打开搜索框

搜索code runner 然后点击安装

111

安装好后点击我圈起来的小齿轮 点击extension settings

111

翻到如下设置,将Run in terminal ,save all files before run 以及save file before run 都勾选上

111

如图

111

然后关闭当前设置页面 返回插件页面继续安装插件 c++插件 我圈起来的俩个都装

111

111

以及有需要的朋友可以装汉化插件 基本就齐活了

这时 回到桌面 建立一个叫code的文件夹 然后右键 选择通过code打开

111

111

打开过后是空的 像我一样 点击我圈起来的那个小符号 就能新建一个文件了

文件名输入后记得加后缀.cpp或者 .c

输入代码

#include<stdio.h>
int main(){
    int a ;
    scanf("%d",&a);
    printf("%d hello world\n",a);
    return 0;
}

按下ctrl alt n就可以运行

111

运行框如图所示

输入111 成功输出 证明没问题

[toc]

简单说一下

工作需要 需要批量修改很多机器上的配置文件,当然,只需要修改一行

配置文件格式为ini 每台机器上的配置文件都不一样,但是一定会有自己需要的那一行

这个时候,肯定会有很多人说,”这不简单吗,readline然后再判断是否包含,然后在修改就行了“

是的,问题的确就是这样做的话未免有些不雅观,都用python,那肯定要找一找有没有读取修改ini这种配置文件的python的库,最好还是python自带的,否则装库也麻烦

假设要修改的ini

[TEST1]
;; 这是注释
TEST_OPT_1 = 1
;; 这也是一处注释
TEST_OPT_2 = dotest
OPT_PATH = /home/auser 

[LISTEN]
;; 只监听本机ip
BIND_IP = 127.0.0.1
;; 监听端口
BIND_PORT = 80
MAX_FDS = 102400
SWITCH_USER = webserver

需要修改LISTEN节的BIND_PORT这个item,将其改为BIND_IP = 8080

库 ConfigParser

服务器是2.6.6 本地是2.7.x 具体忘了,但也正因此埋下了坑 坑后面说

import ConfigParser
import os
import shutil
try:
    from collections import OrderedDict as _default_dict
except ImportError:
    # fallback for setup.py which hasn't yet built _collections
    _default_dict = dict
    
class myconf(ConfigParser.ConfigParser):
    def __init__(self, defaults=None, dict_type=_default_dict,
                 allow_no_value=False):
        ConfigParserLib.ConfigParser.__init__(self,defaults, dict_type,
                 allow_no_value)

    # 这里重写了optionxform方法,直接返回选项名
    def optionxform(self, optionstr):
        return optionstr
def replaceText(path,aim,replace):
    lines = open(path).readlines()
    fp = open(path,'w')
    for s in lines:
        fp.write( s.replace(aim,replace))
    fp.close()
    
currPath = os.path.dirname(os.path.realpath(__file__))
configPath = os.path.join(currPath,"file/test.ini")
backConfigPath = os.path.join(currPath,"file/test.ini.bak")

shutil.copyfile(configPath,backConfigPath)

g_aim = ";"
g_replace = "@"
replaceText(configPath,g_aim,g_replace)

config = myconf()
config.read(configPath)
config.set('LISTEN',"BIND_PORT","8080")
config.write(open(configPath,"w"))
replaceText(configPath,g_replace,g_aim)

print "success"

这是我的替换代码

版本差异 tip

避免了很多的坑 ,但还是出问题了 服务器环境2.6.6 ConfigParser 没有allow_no_value这个属性,起作用是解析无意义的符号

慢慢来缕一缕

保存为小写问题

有人会发现 我是将ConfigParser重载了来使用的,其中,我重载了optionxform方法,因为原本的这个方法是这样的

def optionxform(self, optionstr):
    return optionstr.lower()

为了体现读取配置ini时候的大小写不敏感,python再读取对应内容的时候,都将其小写了,无论本来的内容是大写的也好,小写的也罢,都会变成小写的

于是 你使用这个玩意读取出来再存回去的配置全都会变成小写的,简直离谱

保留注释

接着 我自定义了一个replaceText方法,为什么要用替换方法来替换原本文件的内容呢?

替换的目标是;替换成@

;是ini之中的注释,因为程序是不读取注释的,没错,通过这个库,你重新生成的配置是没有一丝丝注释的——我感觉我拿脚本把所有的配置文件都跑一遍的话,会被骂死~

于是我就开始搜寻,发现需要先把注释替换为别的字符,然后开启allow_no_value=True默认值是False,这样 程序就会读取注释了,再在生成的内容中将@替换为;,我们的注释就保留成功了

真 版本差异问题探讨

前面说了 版本问题很重要

那么该怎么办呢?

个人做法---把2.7的库掏出来

在2.6的python下 用我捞出来的库 当然,记得改名称,不然就导标准库去了

相关链接

关于python:使用ConfigParser将注释写入文件

python自带的configparser模块解析ini文件

protobuf2

很久没有更新博客了,炸尸一下吧,最近遇到protobuf这个协议工具,感觉的确是非常的好用(可以说是除了我在使用的时候遇到问题然后去看官方资料的时候意外,我都是这样觉得的。)

官方教程

protobuf 教程

小白解释

简述protobuf的一些东西

message 是消息体,protobuf里面会定义很多的message来使用。这样说的话会十分的抽象,不过我们可以将其理解为封装了许多数据类型的结构体吧~

使用方法

package school;
message People{
    required string id = 1 ;
    required string name = 2 ;
    required bool sex = 3 [default = false] ; 
}
message Record{
    required string name = 1;
    required double scores = 2;
}
message Records{
    repeated Record record = 1;
}
message Student{
    required People person = 1 ;
    required id = string = 2 ;
    optional Records subject = 3;
}

以上,就是简单的写了一个学校学生信息的demo

其中people是个人信息,包含了身份证号码,名字,性别这三个必要信息,并且性别是默认为false(在这里规定性别为false的话,就是男性,否则是女性)

然后 一个学生必然拥有个人信息,也就是person,我们可以看到,在这里学生的个人信息,就是message People,意味着,我们需要写个人信息的时候,直接使用People这个message是被允许的事情。这样我们就不用重复的写,这个message拥有 id name sex这三个字段了。

然后事学生信息,学生除了message以外,还有一个id,这个id我们规定他是学号,然后还有一个subject,这个信息是他的科目的成绩对。

值得注意的是subject是一个Records的message,并且前面定义的是optional,这事除了required意外的第二个前置的字段了。

我们可以看到,required这个字段的意思是,需要的,也就是一个消息体必需的字段。

而optional的意思则是可选的,也就是说,我传给你的这个消息中,可能有optional这个字段所声明的值,可能也没有。(至于如何判断有无,后面会说)

说完这里,我们看向Records这个message,里面的字段是repeated,意思是这是个数组(当然,也是可有可无的,毕竟数组的元素可能是0嘛~)

其中包含的是Record这个message,里面包含了科目的名字,以及科目的分数。

好了,说完这写过后,我们在看message里面,会发现一个问题,每个message里面的类型后面都跟着一个 ” = 1“ , ”=2“,”=3“这类型的字段,这个表明的是proto在序列化消息时,这些消息所占据的位置,等等。

值得一提的是

如您所见,消息定义中的每个字段都有一个唯一的编号。这些数字用于在消息二进制格式中标识您的字段,一旦您的消息类型被使用,就不应更改。请注意,1 到 15 范围内的字段编号占用一个字节进行编码,包括字段编号和字段类型(您可以在协议缓冲区编码中找到更多相关信息)。16 到 2047 范围内的字段编号占用两个字节。因此,您应该为非常频繁出现的消息元素保留字段编号 1 到 15。请记住为将来可能添加的频繁出现的元素留出一些空间。

您可以指定的最小字段编号为 1,最大字段编号为 2 29 - 1 或 536,870,911。您也不能使用数字 19000 到 19999(FieldDescriptor::kFirstReservedNumberFieldDescriptor::kLastReservedNumber),因为它们是为 Protocol Buffers 实现保留的 - 如果您在.proto. 同样,您不能使用任何以前保留的字段编号。

或许我需要解释一下这段从官方机翻过来的话。

我们的数据会以消息的形式存在,当我们需要发送的时候,其实发送的都是二进制格式的消息。

这个时候,后面的编码其实是会占位置的。

而前面说过了,出了require以外声明的字段,其实是可以不存在于这个二进制的消息体之中的,所以,使用的频繁的内容,最好是占据1-15的编号,这样的话,能过有效的减少二进制编码的体积,也就能提高消息的传输效率。

同时,我们删除字段的时候,只是在协议规范里面删除了,如果你以前有将序列化过后的数据存到db或者某处,然后你又删掉了=4的字段,接着你又给另一个字段规定为=4。emmm,我们还是老老实实举个例子吧

// 修改前
message Student{
    required People person = 1 ;
    required id = string = 2 ;
    optional Records subject = 3;
}
// 修改后
message Student{
    required People person = 1 ;
    required id = string = 2 ;
    optional int64 scores = 3;
}

可以注意到,其中subject被改为scores了,scores在这里理解为总成绩,其类型是64位的int,而非一个Records的subject,可以想到是,当我们拿修改后的消息体去解析以前拥有Records的subject的这个消息(即被序列化为二进制的消息),那是一种灾难性的现场。

对于我们来说,一般是不删除某个字段,将其留在那里,或者是删除他过后,保留这个字段的编号,让后面的字段无法使用这个编号。

比如说

message Student{
    required People person = 1 ;
    required id = string = 2 ;
    reserved 3;
    reserved "subject";
    optional int64 scores = 4;
}

这样,就没有能用=3的字段了,也没有字段能过被命名为subject了。

如果想保留一个区间的字段该怎么办?

使用reserved 9 to 11这样就保留了9到11的字段,也就是9,10,11.

枚举

对于某些值,应该只有某些元素,这就是枚举。

import "mylib/myproto.proto";
enum SubjectName{
    SHUXUE = 0;
    YUWEN = 1;
    YINGYU = 2;
    DILI = 3;
}
message Course{
    required SubjectName subjectName = 1 [ default = SHUXUE];
    optional double scores = 2;
    optional int32 number = 3;
    optional Time time; // 由myproto.proto导入
    optional Addres addres; // 由myproto.proto导入
}

在上面,我用拼音写出了科目的枚举,当然,科目不止这些,但我也就不一一敲出来了。

对于一个课程,我们需要知道这是个什么课程。

每个课程有一个属于自己的枚举,其中我们假设课程默认为数学。

这样的话,就不会存在我们不知道课程。

如果后续由其他的课程的话,我们可以添加新的枚举值——在原来的基础上,这事不受任何影响的。

说到这里,protobuf的具体协议其实就已经说清楚了,其中protobuf支持变量的类型,以及更多细节都在开头给的protobuf链接哪里官方教程

接下来会讲C++之中具体的应用,当然,那是在另一篇文章的事情了。