C++语言基础4:例程讲解(结合在QT的应用) 我们从最基础的语法、每个关键字 / 符号的含义、每一行的执行逻辑逐句拆解全程用新手能理解的表述你可以对着代码一行一行看。例程如下void TemperatureBar::update_data(int base_address, const QVectorquint16 value) { Q_UNUSED(base_address); int offset m_address - m_base_address; if (offset 0 offset value.size()) { quint16 raw_value value.at(offset); float display_value raw_value; if (m_is_shift) { display_value raw_value / 10.0f; } set_value(display_value); } }先整体说下这是 Qt/C 里一个自定义控件类TemperatureBar温度条控件的成员函数功能是接收一批寄存器原始数据计算出当前温度条对应的数据转换成真实温度值后更新控件显示。逐行逐字语法详解第 1 行函数定义函数头void TemperatureBar::update_data(int base_address, const QVectorquint16 value)这是整个函数的声明 定义开头我们拆成每一部分讲void函数的返回值类型。void表示 “空”意思是这个函数执行完之后不会返回任何结果给调用者只负责执行内部的逻辑。TemperatureBar::update_dataupdate_data是函数名。::叫作用域解析符它的作用是明确说明update_data不是普通的全局函数而是TemperatureBar这个类里面的成员函数。补充TemperatureBar是一个自定义的类温度条控件类这个函数是它的功能之一。(int base_address, const QVectorquint16 value)括号里是函数的参数列表也就是调用这个函数时需要传进来的数据这里有 2 个参数第一个参数int base_addressint参数类型整数型。base_address参数名意思是 “基地址”一般代表批量读取寄存器时的起始地址。第二个参数const QVectorquint16 value这部分新手最容易懵我们拆开讲QVectorQt 框架提供的动态数组容器相当于一个可以自动变长的数组用来存一组同类型的数据类似 C 标准库里的std::vector。quint16模板参数说明这个QVector数组里每个元素都是quint16类型。quint16是 Qt 定义的标准类型无符号 16 位整数对应原生 C 的unsigned short占 2 个字节取值范围 0~65535工业通信里一般用来存寄存器的原始数据。引用符号这里表示 “传引用”而不是 “传值”。好处不用把整个数组复制一份直接操作原数据效率很高尤其是数组很大的时候。const常量修饰符和引用搭配叫 “常引用”。作用保证这个数组在函数里只能读、不能改防止代码不小心修改了原始数据同时也是 C 的规范写法。value参数名就是传进来的原始数据数组。第 2 行函数体开始{大括号{ }用来包裹函数的所有执行代码左大括号代表函数逻辑开始最后一行的右大括号代表函数结束。第 3 行消除未使用参数警告Q_UNUSED(base_address);Q_UNUSED()Qt 提供的一个宏可以理解成 Qt 预先定义好的语法标记。作用告诉编译器“base_address这个参数我是故意不用的不要给我报‘未使用的参数’的警告”。为什么传了又不用这个函数一般是统一的接口规范比如所有同类控件的更新函数都必须有基地址这个参数但TemperatureBar这个控件自己的逻辑用不到基地址所以用这个宏来消除编译警告不影响程序运行。第 4 行计算数据在数组中的偏移位置int offset m_address - m_base_address;int offset定义一个整数类型的局部变量名字叫offset意思是 “偏移量 / 下标”。赋值符号把右边的计算结果存到左边的变量里。m_address和m_base_address这两个都是TemperatureBar类的成员变量m_前缀是 C/Qt 的通用命名规范是member的缩写用来一眼区分 “类的成员变量” 和 “函数里的临时变量”。m_address当前这个温度条对应的寄存器地址。m_base_address这一批数据对应的寄存器起始基地址。计算逻辑当前地址 - 起始基地址 这个温度条的数据在数组里的下标位置。 举个例子基地址是 100当前温度条地址是 103那偏移量就是 3对应数组里第 3 个元素数组下标从 0 开始数。第 5 行数组下标越界安全判断if (offset 0 offset value.size()) {这是非常重要的安全防护代码新手最容易漏掉这一步导致程序崩溃。if (条件) { ... }条件判断语句只有括号里的条件成立结果为真才会执行大括号里的代码。条件由两部分组成用连接逻辑与运算符意思是 “并且”只有左右两个条件都成立整体条件才成立。第一个条件offset 0偏移量不能是负数。因为数组下标从 0 开始负数下标是非法的会访问到错误内存。第二个条件offset value.size()value.size()QVector的成员函数返回数组里元素的总个数。意思是偏移量必须小于数组总长度。比如数组有 5 个元素长度是 5合法下标是 0~4所以 offset 必须小于 5。整行作用确保要访问的数组下标是合法的防止数组越界访问数组外面的内存导致程序直接崩溃。只有偏移量在合法范围内才去更新数据。第 6 行取出对应位置的原始数据quint16 raw_value value.at(offset);quint16 raw_value定义一个 16 位无符号整数的局部变量叫raw_value原始值用来存从数组里取出来的寄存器原始数据。value.at(offset)at()是QVector的成员函数作用是获取数组中下标为offset的那个元素。补充QVector 取值有两种写法value[offset]和value.at(offset)。at()会自带越界检查越界时会安全报错[]运算符越界会直接崩溃所以这里用at()是更规范安全的写法。整行意思从数据数组里取出偏移量对应位置的原始 16 位数据存到raw_value变量里。第 7 行初始化显示值float display_value raw_value;float display_value定义一个单精度浮点型变量叫display_value显示值也就是最终要显示在温度条上的真实数值。 raw_value把原始整数值直接赋值给浮点型变量。这里会发生隐式类型转换自动把整数的quint16转成带小数的float。比如原始值是 25转完就是 25.0。为什么要用浮点型因为温度值经常带小数比如 25.6℃整数存不了小数所以需要用浮点型来存最终的显示值。第 8 行判断是否需要数值缩放if (m_is_shift) {m_is_shift类的成员变量bool布尔类型只有true真 /false假 两个值。意思是 “是否需要移位 / 缩放”也就是控制 “原始值要不要除以 10 来还原真实温度” 的开关。为什么要有这个开关工业通信里很多传感器会把温度放大 10 倍 / 100 倍后用整数传输比如 25.6℃存成整数 256但也有的传感器直接传整数温度。所以用这个开关来兼容两种情况初始化控件的时候设置好就行。第 9 行数值缩放还原真实温度display_value raw_value / 10.0f;给display_value重新赋值覆盖掉之前的原始值。raw_value / 10.0f原始值除以 10.0。重点注意10.0f末尾的f表示这是float类型的浮点数。如果写成raw_value / 10整数除以整数那就是整数除法会直接丢掉小数部分比如256 / 10 25写成10.0f就是浮点数除法会保留小数256 / 10.0f 25.6这才是我们要的真实温度。整行意思如果开启了缩放就把原始整数除以 10得到带小数的真实温度值。第 10 行缩放判断结束}右大括号对应第 8 行if (m_is_shift)的左大括号缩放逻辑的代码块到此结束。第 11 行更新温度条控件的显示set_value(display_value);set_value()这是TemperatureBar类或者它的父类的成员函数。作用把计算好的真实数值设置给温度条控件更新界面上的显示 —— 比如更新进度条的长度、更新旁边的数字显示等等。这是整个函数的最终目的前面所有计算都是为了得到正确的数值最后调用这个函数完成界面更新。第 12 行合法数据处理结束}右大括号对应第 5 行if (offset 0 ...)的左大括号合法数据的处理逻辑到此结束。 如果偏移量不合法这一大段代码都会直接跳过什么都不做保证程序安全。第 13 行函数结束}最外层的右大括号整个update_data函数的代码到此全部结束。整体执行流程梳理帮你串起来理解这个函数从调用到结束完整走一遍是这样的外部传入「寄存器基地址」和「一批寄存器原始数据数组」。计算当前温度条对应的数据在数组里的下标位置。检查下标是否合法不合法就直接结束防止崩溃。合法的话取出对应位置的原始 16 位整数。根据控件的缩放开关决定要不要把原始值除以 10得到真实的温度显示值。把最终数值设置给温度条控件更新界面显示。补充两个重要的代码规范m_前缀命名类的成员变量统一加m_前缀是行业通用规范。好处是不用翻定义一眼就能分清 “哪个是类的成员变量”“哪个是函数里的临时局部变量”。越界保护只要操作数组 / 容器就一定要先判断下标是否合法这是避免程序崩溃的最基础也最重要的习惯这段代码的写法非常标准。