C++在线五子棋对战(网页版)项目:实用工具类模块代码实现

news2024/11/24 17:48:06

在线五子棋项目中需要用到的实用工具模块:

1.日志宏:实现程序日志打印

2.mysql_util:数据库的连接和初始化,句柄的消耗,语句的执行

3.json_util:封装实现json的序列化和反序列化

4.string_util:封装实现字符串分割功能

5.file_util:封装文件数据的读取功能(html文件数据的读取)

1.日志宏封装

日志宏的实现,主要实现程序日志的打印。比如打印:

[08:29:32 main.c:28] 文件打开失败。其意思是:在八点29分32秒,在main.c文件的第二十八行,出现了一个主要的错误,该错误为文件打开失败。这时候,我们查看日志,就可以找到错误在哪了。

需要用到的一些接口:

time_t time(NULL);//获取系统时间戳
struct tm *localtime(time_t *t);//根据生成的时间戳,生成一个时间的结构体

//将时间结构体,按照一定的格式组织成字符串放在char空间中,max为s的大小
size_t strftime(char *s,size_t max, const char *format,const struct tm *tm);
//将数据按照一定的格式,写入文件fp中
int fprintf(FILE *fp,char *format,...);

日志宏的实现

#ifndef _M_LOGGER_H_  和 #define _M_LOGGER_H_是预处理器指令,用于防止头文件被重复包含。如果头文件已经被包含了,那么这对指令将会被跳过。

#define部分定义了几个宏常量:

INF 表示正常的日志等级,定义为0。
DBG表示调试信息的日志等级,定义为1。
ERR表示错误信息的日志等级,定义为2。
DEFAULT_LOG_LEVEL表示默认的日志等级,定义为 DBG。

LOG宏定义了一个用于打印日志的函数:

level是日志的等级,用于控制是否打印该日志。
format是日志的格式字符串,类似于 printf 函数。
... 是可变参数,用于传递给格式字符串的值。
do{...}while(0)是为了使该宏可以像函数一样使用。
在宏内部,首先检查DEFAULT_LOG_LEVEL是否大于指定的level,如果是,则跳过后续的代码。然后,获取当前时间,并将其格式化为字符串。最后,使用fprintf函数将日志输出到标准输出流 stdout,包括时间、文件名、行号和格式化的日志内容。

ILOG、DLOG 和 ELOG 是基于 LOG 宏定义的更具体的日志打印函数,分别用于记录正常、调试和错误信息的日志。它们的定义中,会调用 LOG 宏并指定相应的日志等级。

#endif` 表示预处理器指令结束。

其中:通过在宏定义中的 ## 操作符,可以在只有可变参数列表的情况下正常展开,如果没有可变参数传入,则 ## 会将他们连接为空,避免了语法错误。

#ifndef _M_LOGGER_H_
#define _M_LOGGER_H_
#include<stdio.h>
#include<time.h>

#define INF 0 //正常
#define DBG 1 //调试信息
#define ERR 2 //错误信息
#define DEFAULT_LOG_LEVEL DBG //默认日志等级
#define LOG(level,format,...) do{\
    if(DEFAULT_LOG_LEVEL > level) break;\
    time_t t = time(NULL);\
    struct tm *lt = localtime(&t);\
    char buf[32] = {0};\
    strftime(buf,31,"%H:%M:%S",lt);\
    fprintf(stdout,"[%s %s:%d] " format "\n",buf,__FILE__,__LINE__, ##__VA_ARGS__);\
}while(0)

#define ILOG(format,...) LOG(INF,format, ##__VA_ARGS__)
#define DLOG(format,...) LOG(DBG,format, ##__VA_ARGS__)
#define ELOG(format,...) LOG(ERR,format, ##__VA_ARGS__)

#endif
#include"logger.hpp"

int main()
{
    ILOG("五子棋");
    DLOG("项目");
    ELOG("666");
    return 0;
}

mysql_util封装

关于C PAI,请移步-->https://mp.csdn.net/mp_blog/creation/editor/131496582

class mysql_util
{
public:
    //创建数据库的接口:这个接口包含初始化句柄、连接服务器、设置字符集和选择数据库
    /*host:主机名 username:用户名 ossword: 密码 dbname: 要使用的数据库名 port:MYSQL数据库端口号*/
    static MYSQL *mysql_create(const std::string &host,
    const std::string &username,
    const std::string &password,
    const std::string &dbname,
    uint16_t port = 3306)
    {
        //1. 初始化MySQL句柄
        //MYSQL *mysql_init(MYSQL *mysql);
        MYSQL *mysql = mysql_init(NULL);
        if(mysql==NULL)
        {
            ELOG("mysql init failed!");
            return nullptr;
        }

        //2. 连接服务器
        //MYSQL *mysql_real_connect(mysql,host,user,pass,dbname,port,unix_socket,flag)
        if(mysql_real_connect(mysql,host.c_str(),username.c_str(),password.c_str(),dbname.c_str(),port,NULL,0)==NULL)
        {
            ELOG("connect mysql server failed :%s",mysql_error(mysql));
            mysql_close(mysql);
            return nullptr;
        }

        //3.设置客户端字符集
        //int mysql_set_character_set(mysql,"utf8");
        if(mysql_set_character_set(mysql,"utf8")!=0)
        {
            ELOG("set client character failed :%s",mysql_error(mysql));
            mysql_close(mysql);
            return nullptr;
        }

        return mysql;
    }

    //执行语句
    static bool mysql_exec(MYSQL *mysql,const std::string &sql)
    {
        int ret = mysql_query(mysql,sql.c_str());
        if(ret!=0)
        {
            ELOG("%s\n",sql.c_str());
            ELOG("mysql query failed :%s\n",mysql_error(mysql));
            mysql_close(mysql);
            return false;
        }
        return true;
    }
    //释放句柄
    static void mysql_destory(MYSQL *mysql)
    {
        if(mysql!=nullptr)
        {
            mysql_close(mysql);
        }
        return;
    }
};

Jsoncpp-API封装

Json的接口介绍,请移步-->Jsoncpp的使用

#include "logger.hpp"
#include <string>
#include <iostream>
#include<memory>
#include<jsoncpp/json/json.h>
#include<sstream>

class json_util
{
public:
    static bool serialize(const Json::Value &root,std::string &str)
    {
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter>sw(swb.newStreamWriter());
        std::stringstream ss;
        int ret = sw->write(root,&ss);
        if(ret!=0)
        {
            ELOG("Json serialize failed!");
            return false;
        }
        str = ss.str();
        return true;
    }
    static bool unserialize(const std::string &str ,Json::Value &root)
    {
        Json::CharReaderBuilder crb;
        std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
        std::string err;
        bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &root,&err);
        if (ret==false) 
        {
            ELOG("UnSerialize failed!");
            return false;
        }
        return true;
    }

};

string_util字符串分割函数的封装

定义一个静态成员函数split,参数有src,sep和res,其作用分别是:src为需要分割的字符串,sep为分隔符,res是将分割后的字符存储起来。

定义pos,先找到第一个分隔符,然后判断是否可以找到,如果找不到,说明src里面已经没用分隔符了,那么就将src从idx的位置开始的整个字符串放到res中。

如果找到了,首先需要判断分隔符的位置和子字符串的起始位置是否相同,如果相同,说明当前位置的字符是一个分隔符,idx需要往后走。

如果位置不相同,那么就将src中,从idx这个位置,长pos-idx的字符串分割出来放到res中。

class string_util
{
public:
    static int split(const std::string& src,const std::string& sep,std::vector<std::string>& res)
    {
        size_t pos,idx = 0;
        while(idx<src.size())
        {
            pos = src.find(sep,idx);
            if(pos==std::string::npos)
            {
                res.push_back(src.substr(idx));
                break;
            }
            if(pos==idx)
            {
                idx+=sep.size();
                continue;
            }
            res.push_back(src.substr(idx,pos-idx));
            idx  = pos+sep.size();
        }
        return res.size();
    }
};

file_util

参数说明:将filename中的数据读取到body中。

class file_util
{
public:
    static bool read(const std::string& filename,std::string& body)
    {
        //打开文件
        std::ifstream ifs(filename,std::ios::binary);
        if(ifs.is_open()==false)
        {
            ELOG("%s file open failed!",filename.c_str());
            return false;
        }
        //获取文件大小
        size_t fsize = 0;
        ifs.seekg(0,std::ios::end);//偏移量为0,跳转到文件末尾
        fsize = ifs.tellg();//获取当前读写文件相对于文件起始位置的偏移量
        ifs.seekg(0,std::ios::beg);//放回起始位置
        body.resize(fsize);
        //将文件数据读取
        ifs.read(&body[0],fsize);//不能使用body.c_str(),因为它返回的是一个const的起始地址,不能被修改
        if(ifs.good()==false)
        {
            ELOG("read %s file content failed",filename.c_str());
            ifs.close();
            return false;
        }
        //关闭文件
        ifs.close();
        return true;
    }

};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/747960.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Clion开发STM32之W5500系列(四)

W5500协议层之DHCP功能 头文件 #ifndef STM32_VET6_W5500_DHCP_H #define STM32_VET6_W5500_DHCP_H#include "socket.h"#define DEVICE_ID "w5500" #define IP_CONFLICT_STR "CHECK_IP_CONFLICT" #define DHCP_FLAGSBROADCAST 0x8000 /* …

π141E30S 200Mbps四通道数字隔离器兼容代替NSi8141S0

π141E30S荣湃深力科 200Mbps四通道数字隔离器兼容代替NSi8141S0 π141E30S数字隔离器具有出色的性能特 征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器。 在不需要调制和解调的情况下&#xff0c;实现电压信号跨越隔离介质精 准传输。 π141E30S传输通道…

利用ffmpeg使用脚本+excel批量合成视频

起因是忘了是什么时候&#xff0c;下载的视频是被切割的一个一个的&#xff0c;所以网上找了方法&#xff0c;利用ffmpeg批量进行了批量合成&#xff0c;这里记录一下&#xff0c;并用gpt解释一下脚本含义。 1、文件名批量转mp4格式 如果文件名不规范&#xff0c;可以利用exce…

spark Structured Streaming checkpoint参数优化

目录 1 问题描述2 分析 checkpointLocation 配置 2.1 checkpointLocation 在源码调用链2.2 MetadataLog&#xff08;元数据日志接口&#xff09;3 分析 checkpointLocation 目录内容 3.1 offsets 目录3.2 commitLog 目录3.3 metadata 目录3.4 sources 目录3.5 sinks 目录4 解决…

跨站脚本攻击XSS

​​​​​​1、漏洞原理及防御 XSS又叫CSS (CrossSiteScript),因为与层叠样式表(css)重名,所以叫Xss&#xff0c;中文名叫跨站脚本攻击。 xss攻击&#xff0c;主要就是攻击者通过“html注入”篡改了网页&#xff0c;插入了恶意的脚本&#xff0c;从而在用户浏览网页时&#…

迅为龙芯3A5000_7A2000COMe_模块和主板

龙芯 3A50007A2000 COME 采用全国产龙芯 3A5000 处理器&#xff0c;基于龙芯自主指令系统 (LoongArche)的 LA464 微结构&#xff0c;并进一步提升频率&#xff0c;降低功耗&#xff0c;优化性能。桥片采用龙芯 7A2000&#xff0c;支持 PCIE 3.0、USB 3.0 和 SATA 3.0、显示接口…

单独编译 Android 固件-打包 update.img-iTOP-RK3588开发板

进入到 3588-android12 文件夹&#xff0c;输入以下命令设置 java 版本为 1.8 版本&#xff0c;如下图所示: source javaenv.sh java -version 输入以下命令使能编译环境: source build/envsetup.sh lunch rk3588_s-userdebug 执行完上述命令&#xff0c;如果需要编译 uboo…

如何破解滑动验证码?

本文通过自动化查询域名或公司的备案信息&#xff0c;来演示其中图片滑动验证码的破解方式&#xff0c;以此来思考验证码的安全性问题&#xff0c;思考如何设计出安全性更高的验证码。 注意&#xff1a;破解验证码进行网络内容抓取可能是一种违规行为&#xff0c;可以以此进行验…

西门子PLC硬件编程需要注意的几个要点

往往一个好的编程程序习惯可以让事情事半功倍。用正确的逻辑思维和方法去写程序&#xff0c;一方面可以减少出错&#xff0c;另一方面就是方便检查程序里出现的bug。下面就为大家盘点一下&#xff0c;西门子PLC的一些硬件编程的好习惯。 1、关于选型 项目开始需要统计出IO点表…

Linux嵌入式项目-智能家居

一、资料下载 二、框架知识 三、MQTT通信协议 1、上位机APP主要工作 1.wait for msg / while(1)订阅等待消息 2.处理消息 客户端创建了两个线程&#xff0c;一个线程用于发布消息&#xff0c;一个线程用于监听订阅消息 &#xff08;那我的仿真系统也可以啊&#xff0c;一个…

《AutoSar实战》DIO配置

文章目录 前言一、配置过程1&#xff0c;选择引脚2&#xff0c;DIO模块配置1&#xff09;新建DioChannel 3&#xff0c;PORT模块配置4&#xff0c;保存并生成DIO&#xff0c;PORT模块 二、实现并验证1&#xff0c;调用函数接口2&#xff0c;示波器测量周期 总结 ->返回总目录…

富士施乐/Fuji Xerox SC2022 CPS DA 彩色激光复印机不能扫描的解决方法

一台富士施乐/Fuji Xerox SC2022 CPS DA 彩色激光复印机用网线连接的&#xff0c;有分配的IP地址&#xff0c;有三台电脑连接&#xff0c;可打印&#xff0c;但是不能扫描。 驱动也没问题&#xff0c;找了一台电脑先删除了打印机&#xff0c;在官网下载了驱动重新安装&#xff…

【Spring学习一】简单认识Spring是什么?——框架

目录 1、为什么要学习Spring&#xff1f; 2、Spring是什么&#xff1f; 1、IoC是什么&#xff1f; 2、进一步通过代码演示理解IoC 3、怎么理解容器&#xff1f; 4、知道DI与IoC的区别&#xff1f; 1、为什么要学习Spring&#xff1f; 我们常说的Spring 指的是 Spring Fra…

Microsoft 已经发布了7月份的产品安全问题修复报告。

&#x1f525;Microsoft 已经发布了7月份的产品安全问题修复报告。我们建议您关注趋势性漏洞&#xff0c;即那些已经或即将被攻击者积极利用的漏洞。 7月份报告中的两个危险漏洞&#xff1a; CVE-2023-32049和CVE-2023-35311。 CVE-2023-32049漏洞允许网络犯罪分子绕过Window…

卫星图片的Classification_model

Tensorflow版本&#xff1a;2.6.0 使用的是CNN神经网络&#xff0c;网络结构在最后给出 飞机和湖泊的卫星图片二分类网络 数据集请点击链接&#xff1a;https://www.kaggle.com/datasets/yo7oyo/lake-plane-binaryclass 数据集的构成&#xff1a;airplane: 700 张&#xff0c; …

着眼未来砥砺前行,知了汇智携西南交大学生走进企业参观学习

随着数字化转型推进的深入&#xff0c;企业对数字化人才的需求量大幅增长&#xff0c;人才需求结构也发生显著在变化。为加强学生与企业的接触&#xff0c;拓展专业视野&#xff0c;对接行业需求&#xff0c;激发学生对所学专业的兴趣&#xff0c;明确自己学习的目标&#xff0…

NC19 连续子数组的最大和

import java.util.*; public class Solution {public int FindGreatestSumOfSubArray(int[] array) {//记录到下标i为止的最大连续子数组和int[] dp new int[array.length]; dp[0] array[0];int maxsum dp[0];for(int i 1; i < array.length; i){//状态转移&#xff1a;…

优雅实现垂直SeekBar:不继承Seekbar、不自定义View

目录 0 前言 关于自定义View 1 实现竖直SeekBar 1.1 XML布局解析 1.1.1 套一层FrameLayout 1.1.2 SeekBar去除左右间距 1.1.3 SeekBar高度无法设置 1.1.4 SeekBar背景设置 1.1.5 底部View尺寸和距底部距离不硬编码 1.2 自定义样式属性与主题 1.2.1 自定义样式属性 …

应急管理大屏助力暴雨天气下的水灾防范

随着气候变化和城市化进程的加剧&#xff0c;暴雨天气引发的水灾风险日益凸显。在面对这种自然灾害时&#xff0c;如何高效、及时地应对、减轻损失成为了当务之急。水灾应急管理平台的可视化大屏为相关部门和决策者提供了实时、全面的信息展示和决策支持&#xff0c;大大提升了…

每天5个好用的实用工具链接分享(第1弹)

每天5个好用的实用工具链接分享&#xff08;第1弹&#xff09; 1、免费PPT模板网站2、科研狗租用GPU跑模型网站3、在线正则测试网站4、免费数据集下载网站5、在线curl命令转代码网站6、号外 1、免费PPT模板网站 【链接】&#xff1a;https://www.ypppt.com/ 【网站名】&#x…