波兰喜嘎嘎

之前做的一个项目,需要用c++写一个服务去访问和控制硬件。这个服务是同事写的,今年年中离职了,很自然地,轮到我接手。

一、认知

我捣鼓了几天,勉强读懂一点原来的代码,并在原来基础上,做了一些修改,计有
1)增加从数据库中读取新数据;
2)修改原有功能;
3)重构部分代码

总的感觉,或者说是收获,就是

1、语法比较怪异

比如,对象的属性或方法,,要用对象->属性或对象->方法()来表示

LIMClass* lim_cls = mstId_LIMClass_map_mbs_ptr->at(master_id);
lim_cls->stop();

这样的话,如果c++支持lambda表达式(还真支持),岂不容易混淆?

然后有命名空间与其中的方法、变量或类

std::string str_master_id = std::to_string(mstId);

2、指针泛滥

也许C语言最大的特色就是指针了,而C++的指针与C基本一致。我过去的印象就是,这是一个难点。总的来说,指针指向对象的内存地址。这就相当于c#或java里的引用类型变量。

以下是一个定义指针并使用的例子:

//千万不能写成 int *ptr = 10;错误!
int value = 10;
int *ptr = &value;//定义一个名为ptr的指针,指向变量value的内存地址
std::cout << *ptr << std::endl; //输出指针指向的地址所存储的内容:结果是输出10
std::cout << ptr << std::endl; //输出指针指向的地址:结果是输出0x1234

我认为容易令人感到困惑。定义指针的时候,需要带上星号(*),但指针名称本身其实是不带星号的,如果指针前面带上星号,代表的不是指针,而是指针指向地址所存储的内容,也就是值!仔细看看上面的例子就知道了。当然,定义时,星号可以挨近指针名称,也可以挨近类型,意思是一样的。例如以下例子中,ptr1和ptr2是等价的:

int value = 10;
int* ptr1 = &value;
int *ptr2 = &value;

不过,紧挨类型的话,有时可能会让人误解:

int* ptr1, ptr2;  // ptr1是int*类型,ptr2是int类型
int *ptr1, *ptr2;  // ptr1和ptr2都是int*类型

令人发指的是,还可以来一个指向指针的指针(指针本身也有内存地址):

int value = 10;  // 定义一个int类型的变量
int *ptr1 = &value;  // ptr1指向value
int **ptr2 = &ptr1;  // ptr2指向ptr1// 输出各个值和地址
std::cout << "value: " << value << std::endl;  // 输出10
std::cout << "ptr1: " << ptr1 << std::endl;    // 输出value的地址
std::cout << "*ptr1: " << *ptr1 << std::endl;  // 输出10
std::cout << "ptr2: " << ptr2 << std::endl;    // 输出ptr1的地址
std::cout << "*ptr2: " << *ptr2 << std::endl;  // 输出ptr1的值(即value的地址)
std::cout << "**ptr2: " << **ptr2 << std::endl; // 输出10

3、特别喜欢操作内存

从指针就可以看出来,C++特别喜欢直接操作内存。这可能是它所谓执行效率非常高的一个原因。但凡事有利弊,直接操作内存,一不小心就内存泄漏。

以下是一个通过静态键值实现全局共享哈希表的例子(这好像跟直接操作内存没有什么关系,先凑合看吧):

#include <iostream>
#include <unordered_map>
#include <string>class GlobalData {
public:// 静态成员变量,全局共享的哈希表static std::unordered_map<int, std::string> sharedMap;// 添加数据到哈希表static void addData(int key, const std::string& value) {sharedMap[key] = value;}// 从哈希表中获取数据static std::string getData(int key) {auto it = sharedMap.find(key);if (it != sharedMap.end()) {return it->second;} else {return "Key not found";}}// 删除哈希表中的数据static void removeData(int key) {sharedMap.erase(key);}// 打印哈希表中的所有数据static void printData() {for (const auto& pair : sharedMap) {std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;}}
};// 静态成员变量的初始化
std::unordered_map<int, std::string> GlobalData::sharedMap;int main() {// 添加数据GlobalData::addData(1, "Value1");GlobalData::addData(2, "Value2");GlobalData::addData(3, "Value3");// 获取数据std::cout << "Data for key 1: " << GlobalData::getData(1) << std::endl;std::cout << "Data for key 2: " << GlobalData::getData(2) << std::endl;std::cout << "Data for key 3: " << GlobalData::getData(3) << std::endl;// 打印所有数据std::cout << "All data in the shared map:" << std::endl;GlobalData::printData();// 删除数据GlobalData::removeData(2);// 再次打印所有数据std::cout << "All data in the shared map after removal:" << std::endl;GlobalData::printData();return 0;
}

GlobalData 类包含一个静态成员变量 sharedMap,这是一个 std::unordered_map<int, std::string> 类型的哈希表,用于存储全局共享的数据。由于其是静态的,因此调用的地方无须构造实例,就能使用,存入或读取其中的数据。

4、访问硬件

c++这种语言从语法上看,没有什么优势,学习成本还高,一般不用来开发普通的应用程序,其强项应该在于直接与底层和硬件打交道。

比如某电源支持编写上位机软件进行访问和控制。我们项目中就需要读取它的数据,以及对它进行控制。

1)这是它的控制指令和控制后返回消息格式:
在这里插入图片描述
2)其中设置电源控制模式指令为:
在这里插入图片描述

3)相关代码

#define READ_CMD 0x03		//读指令
#define WRITE_CMD 0x06		//写指令
#define READ_ERROR 0x83		//读取错误
#define WRITE_ERROR 0x86	//写入错误/*
* 电源控制模式:本地/远程
*/
bool MyPower::setControlMode(int mode) {this->ctrl_mode = mode;unsigned char cmd[] = { this->address, WRITE_CMD, 0x01, 0x13, 0x00, mode, 0x00, 0x00 };//控制指令setCrcValue(cmd, 6);//生成CRC校验码unsigned char recv_data[32];//用于接收返回结果this->send_and_recv_data(cmd, recv_data, 8, 8);return recv_data[1] != WRITE_ERROR;
}void MyPower::send_and_recv_data(unsigned char* sendData, unsigned char* recv_data, int send_len, int recv_len) {std::lock_guard<std::mutex> lock(this->socket_mtx);bool is_happen_error = false;while (true) {if (is_happen_error) {this->init_socket();is_happen_error = false;}unsigned char sendData_[32];memcpy(sendData_, sendData, send_len);int bytesSent = send(this->clientSocket, reinterpret_cast<char*>(sendData_), send_len, 0);if (bytesSent == SOCKET_ERROR) {char out_buf[64];strcpy(out_buf, this->ipaddr);strcat(out_buf, " Failed to send data.");strcat(out_buf, "\n");printf(PREFIX "%s", out_buf);closesocket(this->clientSocket);WSACleanup();is_happen_error = true;continue;}unsigned char recvData[0x60];int bytesReceived = 0;bytesReceived = recv(this->clientSocket, reinterpret_cast<char*>(recvData), recv_len, 0);if (bytesReceived == SOCKET_ERROR) {int errCode = WSAGetLastError();/*调用 WSAGetLastError() 获取具体的错误码。常见的错误码及其含义:10060 (WSAETIMEDOUT):接收超时,可能是服务器未能在指定时间内返回数据。10054 (WSAECONNRESET):连接被对方重置,可能是服务器关闭了连接。10053 (WSAECONNABORTED):连接中止,表明连接被意外关闭。*/std::cerr << PREFIX << "Failed to receive data. Error code: " << errCode << std::endl;closesocket(this->clientSocket);WSACleanup();is_happen_error = true;continue;}else {memcpy(recv_data, recvData, recv_len);break;}}
}

值得一提的是,指令cmd在定义时是一个数组,但当它作为参数传递,无论是在setCrcValue()还是在
send_and_recv_data(),都以指针的形式出现。这是因为,

**在C++中,当数组作为函数参数传递时,数组会退化为指向其第一个元素的指针。**数组名在大多数情况下会被解释为指向其第一个元素的指针。这种行为在以下情况下发生:

作为函数参数传递。
用于指针运算(如 cmd + 1)。
用于 sizeof 运算符以外的其他上下文。

二、小结

我只在读书的时候写过c++,当时c++作为一门课程,是为了讲述面向对象。在此之前,我们还学过pascal,一种面向过程语言。教材之所以选pascal,据说是因为其风格较为优美、规范,特别利于编程语言教学。当然了,据说后来的delphi语法跟pascal保持一致,不过我没有用过。那时候,我们计算机系布置的一些上机作业,比如图形学、密码学、计算方法、操作系统等,都用c++(borland c++)来编码。当时还是ms-dos时代,win95刚出来不太久,我们编码,相当一部分时间是花在写界面上,比如下拉菜单、支持鼠标点击等等。

出来工作以后,就再没有用过c++了。我曾经想学一下visual c++,但感到十分艰深晦涩,加上与工作没有关系,进展如蜗牛,形同放弃。那时java刚兴起,与高薪挂钩,但我不知道怎么想的,也没有涉足。工作第一年用的是visual foxpro,一种与数据库关系比较紧密的工具,整天拖控件,捣鼓增删改查。人啊,糊涂,懒惰。大约这就是命吧。

时间过得真快,一眨眼,20多年就过去了。其实像我这么老的,没有捞到管理岗位,至少也应该精通汇编、C、C++,能普通程序员所不能,筑起一条护城河才对,但我就没有,仍然每天捣鼓增删改查。总之没有技术含量。可替代性特别强。

喜嘎嘎,波兰喜嘎嘎,咦吔。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于LORA的一主多从监测系统_4G模块上巴法云

临时添加一个更新&#xff0c;更换云平台为巴法云&#xff0c;事情的起因是因为阿里云这个老六&#xff0c;早上睡了一觉起来发短信告诉我云平台给我停了&#xff0c;得交钱&#xff0c;好嘛&#xff0c;不过也没办法现在这基本都收费&#xff0c;当然还有onenet可以用&#xf…

.NET Core WebApi第4讲:控制器、路由

一、控制器是什么&#xff1f; 1、创建一个空的API控制器&#xff1a;TestController.cs 2、里面有一个类叫TestController&#xff0c;把它叫做控制器 因为它继承了ControllerBase类&#xff0c;ControllerBase类里提供了一系列的方法&#xff0c;使得TestController这个类具…

Java面试经典 150 题.P55. 跳跃游戏(009)

本题来自&#xff1a;力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解&#xff1a; class Solution {public boolean canJump(int[] nums) {int…

计算机网络网络层笔记

互联网提供的两种服务 1.虚电路服务 2.数据报服务 需要记住的是现在只用第二种也就是数据报服务 网际协议IP 物理层的中断系统:转发器(hub) 链路层的中断系统:交换机 网络层的中断系统:路由器 网络层以上:网关 如上图所示,网关是用来访问其他的网段的一个接口,网关的地…

【热门主题】000015 大数据治理:开启数据价值新纪元

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

CentOS8.5.2111(4.1)数据中心主DNS部署

【背景】 某公司的数据中心DC&#xff0c;要架设DNS服务器负责解析“学生姓名缩写.cqie”的域名解析工作。DNS服务器的FQDN&#xff08;完全正式域名标识&#xff09;为dns.姓名.cqie&#xff0c;IP地址为192.168.学号.66。要求为以下域名实现正反向域名解析服务。&#xff08…

【C/C++】模拟实现strlen

学习目标&#xff1a; 使用代码模拟实现strlen。 逻辑&#xff1a; strlen 需要输入一个字符串数组类型的变量&#xff0c;并且返回一个整型类型的数据。strlen 需要计算字符串数组有多少个元素。 代码1&#xff1a;使用计数器 #define _CRT_SECURE_NO_WARNINGS 1 #include&…

渗透测试-百日筑基—SQL注入篇时间注入绕过HTTP数据编码绕过—下

day8-渗透测试sql注入篇&时间注入&绕过&HTTP数据编码绕过 一、时间注入 SQL注入时间注入&#xff08;也称为延时注入&#xff09;是SQL注入攻击的一种特殊形式&#xff0c;它属于盲注&#xff08;Blind SQL Injection&#xff09;的一种。在盲注中&#xff0c;攻击…

Linux 文件内容显示

文件内容显示 浏览普通文件 文件内容查看 cat 命令 作用&#xff1a;查看文件内容&#xff0c;适合数据量较少 格式&#xff1a; cat -参数 文件名 参数&#xff1a; -n &#xff1a;显示行号&#xff0c;加上 -b &#xff1a;文件中所有非空行增加行号&#xff0…

ALIGN: Tuning Multi-mode Token-level Prompt Alignment across Modalities

文章汇总 当前的问题 目前的工作集中于单模提示发现&#xff0c;即一种模态只有一个提示&#xff0c;这可能不足以代表一个类[17]。这个问题在多模态提示学习中更为严重&#xff0c;因为视觉和文本概念及其对齐都需要推断。此外&#xff0c;仅用全局特征来表示图像和标记是不…

linux学习笔记 Ubuntu下的守护进程supervisor安装与多项目部署

我这里首先是在本地WSL上进行安装&#xff0c;WSL2的是ubuntu 24.04&#xff0c;之后又再正式环境的ubuntu 20.04上安装&#xff0c;再次记录一下。 1、首先安装supervisor apt install -y supervisor 2、创建配置文件 echo_supervisord_conf > /etc/supervisor/supervisor…

Linux特种文件系统--tmpfs文件系统前传:虚拟内存子系统

虚拟内存子系统是操作系统中的一个重要组成部分&#xff0c;它负责管理和优化计算机的内存使用。虚拟内存的概念允许操作系统为每一个进程创建一个虚拟地址空间&#xff0c;这个空间比实际物理内存要大得多。虚拟内存子系统通过将部分虚拟地址映射到物理内存&#xff0c;部分映…

【测试工具】通过Jmeter压测存储过程

目录 一、存储过程准备1.1、 建立空表1.2、 建立存储过程1.3、调试 二、测试工具准备三、工具配置及执行3.1、配置JDBC Connection Configuration&#xff1a;3.2、配置吞吐量控制器3.3、配置JDBC Request 一、存储过程准备 1.1、 建立空表 CREATE TABLE test_data ( id NUMB…

安宝特分享 | AR技术引领:跨国工业远程协作创新模式

在当今高度互联的工业环境中&#xff0c;跨国合作与沟通变得日益重要。然而&#xff0c;语言障碍常常成为高效协作的绊脚石。安宝特AR眼镜凭借其强大的多语言自动翻译和播报功能&#xff0c;正在改变这一局面&#xff0c;让远程协作变得更加顺畅。 01 多语言翻译优势 安宝特A…

vivado-vitis-2024.1 ps_hello_world 实验

实验环境 vivado&#xff1a;2024.1 vitis&#xff1a;2024.1 核心板&#xff1a;ZYNQ-7020 实验内容 实验PS端串口打印 "Hello world " 硬件配置 打开vivado2024&#xff0c;新建一个工程 点击 Create Block Design 开始IP配置 首先连接线 然后点击自动连接…

[GXYCTF 2019]Ping Ping Ping 题解(多种解题方式)

知识点: 命令执行 linux空格绕过 反引号绕过 变量绕过 base64编码绕过 打开页面提示 "听说php可以执行系统函数&#xff1f;我来康康" 然后输入框内提示输入 bjut.edu.cn 输入之后回显信息,是ping 这个网址的信息 输入127.0.0.1 因为提示是命令…

《神经网络助力战场车辆及部件损毁识别与评估》

《神经网络助力战场车辆及部件损毁识别与评估》 一、战场车辆损毁评估的重要意义二、传统战场车辆损毁评估方法&#xff08;一&#xff09;视觉评估法&#xff08;二&#xff09;仪器检测技术 三、神经网络在战场车辆损毁评估中的应用案例&#xff08;一&#xff09;射击毁伤评…

K8S配置storage-class

简介 Kubernetes支持NFS存储&#xff0c;需要安装nfs-subdir-external-provisioner&#xff0c;它是一个存储资源自动调配器&#xff0c;它可将现有的NFS服务器通过持久卷声明来支持Kubernetes持久卷的动态分配。该组件是对Kubernetes NFS-Client Provisioner的扩展&#xff0…

Redis 主从同步 总结

前言 相关系列 《Redis & 目录》《Redis & 主从同步 & 源码》《Redis & 主从同步 & 总结》《Redis & 主从同步 & 问题》 参考文献 《Redis的主从复制和哨兵机制详解》 概述 简介 主从同步的本质是数据复制机制。主从同步机制用于将master…

Android 圆形进度条CircleProgressView 基础版

一个最基础的自定义View 圆形进度条&#xff0c;可设置背景色、进度条颜色&#xff08;渐变色&#xff09;下载进度控制&#xff1b;可二次定制度高&#xff1b; 核心代码&#xff1a; Overrideprotected void onDraw(NonNull Canvas canvas) {super.onDraw(canvas);int mW g…