news 2026/10/30 19:04:11

Qt无线连接与软键盘实现:WiFi扫描、连接及输入方案详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt无线连接与软键盘实现:WiFi扫描、连接及输入方案详解

简介:面向Linux平台需要添加WiFi图形管理能力的嵌入式或桌面开发者,这份资源以Qt框架完成无线网络界面,通过系统wpa_supplicant服务实现附近WiFi的搜索、列表显示与加密连接,兼容WEP、WPA2等常见加密方式。密码输入处集成了软键盘,并带有拼音输入法支持,可减少实体键盘依赖,适合触屏设备使用。压缩包共21个文件,大小2.94MB,主要包含5个cpp源文件、4个h头文件、3个ui界面文件、2个qrc资源文件和若干背景图片,源码、界面布局、图标资源及工程配置分离清晰,便于直接载入Qt工程查看运行。功能上支持一键刷新扫描,最多同时显示20个WiFi热点,连接对话框可自动弹出软键盘,交互链路完整,目前已有1011人浏览学习。对于不熟悉wpa_supplicant调用机制的开发者,这份工程提供了从界面到系统调用的完整示例,可在此基础上修改认证逻辑或UI,也可作为Qt访问底层无线服务的参考模板。

1. 用Qt做WiFi搜索连接与软键盘:先回答这四个问题再动手

如果你在工控触摸屏或自助终端上做过设置界面,大概率逃不掉这个需求:用户要像手机一样搜索周边WiFi、点一下连接、再在弹出的软键盘里输无线密码。标题里的“Qt无线连接 WIFI搜索显示连接 可弹出软键盘”是嵌入式Qt里最常见的“设置页三件套”。可真正动手会发现一个反直觉的事实:Qt自己根本不提供无线扫描和连接接口,QNetwork只管收发数据包。WiFi扫描靠系统的NetworkManager或Windows的Wlan API,Qt只负责把结果画成界面;软键盘也不是自带功能,得接入Qt Virtual Keyboard或自绘键盘窗口。动手前先想清楚四个问题:目标系统是Linux还是Windows、触摸屏分辨率多大、程序有没有root/管理员权限、要不要保存连接密码。这四个答案决定后面所有选型。

2. 扫描周边WiFi:QProcess调nmcli的最小实现与Windows Wlan API预案

2.1 Qt没有无线管理接口,为什么要走系统命令

Qt的Network模块提供QNetworkInterface、QNetworkConfiguration这类类,但它们是“看配置”用的,不提供扫描热点、发起关联握手、保存密码这些真正的无线管理能力。Windows上可以调Wlan API,Linux上有两条路:NetworkManager的DBus接口和nmcli命令行。DBus是正路子,协议稳定、信息量大,但写起来很啰嗦——要引入QtDBus,处理DBus信号、成员、路径,一个小接口动辄几百行。nmcli是NetworkManager官方命令行工具,把DBus操作全都包好了,QProcess启动nmcli、读标准输出、按文本解析,对“快速做成一个设置页”是最省事的路径。

常见做法是以nmcli为主力,把DBus留作需要实时信号(比如系统网络变化提示)的补充。我一般会把扫描、连接、查状态分别封装成独立的小类,避免一个类里塞满QProcess回调。QProcess本身是异步的,每次只发一个命令、用finished信号收结果,比用阻塞式调用来得稳。Qt自带的命令行工具确实不少,但WiFi扫描这件事不在Qt的职权范围内,落到系统命令或系统API上才是正解。

2.2 nmcli扫描命令的封装与带信号强度的列表解析

最小可跑的扫描命令长这样:

nmcli -t -f SSID,SIGNAL,SECURITY dev wifi list

-t(terse)模式不带表头、用冒号分隔字段,-f只输出SSID、信号强度、加密方式三列。完整扫描结果通常有十几行,一次跑下来不到一秒。注意有些网卡驱动扫描结果带乱码或空SSID,初始版本先只解析非空SSID。

下面是QProcess封装的最小代码:

#include <QProcess> #include <QStringList> #include <QDebug> void WifiScanner::startScan() { if (m_proc && m_proc->state() == QProcess::Running) { m_proc->terminate(); // 上一次还没跑完,先停掉 m_proc->waitForFinished(200); } m_proc = new QProcess(this); connect(m_proc, &QProcess::finished, this, [this](int exitCode, QProcess::ExitStatus status) { if (exitCode != 0 || status != QProcess::NormalExit) { qWarning() << m_proc->readAllStandardError(); return; } QByteArray out = m_proc->readAllStandardOutput(); parseScanResult(QString::fromUtf8(out)); // 统一用UTF-8进业务层 }); // 关键:用参数列表,不要拼shell字符串 m_proc->start("nmcli", QStringList() << "-t" << "-f" << "SSID,SIGNAL,SECURITY" << "dev" << "wifi" << "list"); }

解析函数:

void WifiScanner::parseScanResult(const QString &raw) { m_networks.clear(); const QStringList lines = raw.split('\n', Qt::SkipEmptyParts); for (const QString &line : lines) { QStringList parts = line.split(':'); if (parts.size() < 3) continue; QString ssid = parts[0]; if (ssid.isEmpty()) continue; // 隐藏SSID或未解析到的先跳过 int signal = parts[1].toInt(); // 0~100 QString security = parts[2]; // 同一个SSID可能被多个热点重复上报,按SSID+security去重 bool exists = std::any_of(m_networks.cbegin(), m_networks.cend(), [&](const WifiInfo &w) { return w.ssid == ssid; }); if (!exists) { m_networks.append({ssid, signal, security}); } } emit scanFinished(); }

用QProcess::start而不是QProcess::execute,因为execute是阻塞式的,扫描期间界面会卡死。finished回调里先读stderr再读stdout,两个管道是独立的,先读完一个再读另一个避免缓冲区互锁。如果想区分2.4G和5G,把-f里加一个CHAN字段,信道大于36的一般是5G,这对后续按频段排序很有用。

2.3 Windows触摸一体机的netsh/Wlan API后备方案

如果目标设备是Windows触摸一体机或Windows板卡,nmcli就没了。备选方案有两个。netsh容易上手:

netsh wlan show networks mode=bssid

输出按“SSID 1 : xxx”分组,下面带信号、加密等信息。netsh输出定位于人类可读,解析时按SSID行和“信号 : xx%”配对。连接用netsh wlan connect name=配置文件 ssid=xxx,但前提是先配置好WLAN配置文件,对临时机器很不友好。

量产更稳的是Wlan API,链接wlanapi.lib,在pro里写LIBS += -lwlanapi。核心流程是:WlanOpenHandle获取句柄,WlanGetNetworkBssList拿到WLAN_BSS_LIST,每个entry里都有dot11Ssid和信号强度;连接用WlanConnect配合WLAN_CONNECTION_PARAMETERS指定SSID和密码。代码量比nmcli方案大不少,但Windows下不需要额外服务依赖。如果只是给演示样机做一版,netsh够用;要量产,直接上Wlan API,编码和正则的坑会让你怀疑人生。

2.4 隐藏SSID、扫描限频和DBus方案的取舍

隐藏SSID的网络在扫描列表里默认不出现,nmcli也扫不到。要做完整,得在连接时直接传SSID让网卡定向关联,或者让用户手动输入SSID再连。我一般不做隐藏网络扫描,而是把“手动添加网络”做成一个输入框,走连接命令的SSID直连逻辑。

还有一个容易踩的点:NetworkManager对扫描有限频,连续两次scan太近,第二次可能拿到上次的缓存结果,甚至直接返回空。所以扫描按钮要做冷却,两次扫描间隔至少5秒。如果单靠DBus的RequestScan触发网络级扫描,这个限频是绕不开的。DBus方案本身没什么问题,只是对产品来说,QProcess读文本的调试成本远低于QtDBus的类型签名调试。除非你的产品需要被动感知系统网络变化(比如断网弹提醒),否则先用nmcli,别一开始就上DBus。

3. 显示WiFi列表并触发连接:QListWidget、去重排序与异步状态机

3.1 用QListWidget承载扫描结果并区分信号强度

扫描结果拿到后,显示层有个简单的选择:QListWidget或QTableView。设置页一般只需要“点一项去连接”,QListWidget就够。想显示更多字段时可以用QTableView,但普通WiFi选择页展示太多列反而难看。我倾向QListWidget加自定义委托,既保留简单性,又能在item里画信号图标。

每个item用Qt::UserRole存SSID和信号值,显示文本只放SSID名称。信号强度不要靠Unicode字符“▂▄▆█”表示,不同字体的显示宽度不一致,在触摸屏上经常错位。更稳的做法是画一个四格信号条QPixmap存成icon:

void WifiPage::refreshList(const QVector<WifiInfo> &networks) { ui->listWidget->clear(); for (const WifiInfo &w : networks) { QListWidgetItem *item = new QListWidgetItem(ui->listWidget); item->setText(w.ssid); item->setData(Qt::UserRole, w.ssid); item->setData(Qt::UserRole + 1, w.signal); item->setIcon(signalIconForLevel(w.signal)); // 自定义绘制或资源图 ui->listWidget->addItem(item); } }

刷新时不要每次都全清全插。clear再addItem在数据量大时会闪,触摸屏设备性能一般,闪烁感更明显。正确做法是先对比新旧列表的SSID集合,只增删差异项;数据量小时用QSignalBlocker包住插入操作也能缓解。排序上按signal降序排列,但把“已连接”的网络置顶。判断已连接用nmcli -t -f IN-USE,SSID,SIGNAL dev wifi list,IN-USE字段为*的就是当前网。

3.2 中文SSID和特殊字符在列表里的编码处理

中文SSID是这功能第一个拦路虎。nmcli在绝大多数Linux发行版里输出UTF-8,但Qt程序跑在LC_ALL=C或locale缺失的环境时,直接用QString::fromLocal8Bit会把它按ASCII/ANSI解释,中文全变问号。反过来,Windows的netsh输出是当前代码页(GBK常见),必须用QString::fromLocal8Bit。

// Linux/nmcli场景 QString ssid = QString::fromUtf8(lineBytes); // Windows/netsh场景 QString ssid = QString::fromLocal8Bit(lineBytes);

最坑的现场是显示正常但连不上:显示层用UTF-8的QString,连接层却把它用toLocal8Bit转回本地编码拼装命令,本地locale是C时中文被转成问号。正确处理是显示层统一UTF-8 QString,连接层直接把QString传给QProcess参数列表,让QProcess按系统locale编码后再发给nmcli。想让nmcli固定吃UTF-8,可以在命令前加LC_ALL=C.UTF-8 nmcli ...,但精简版系统未必有C.UTF-8 locale。程序启动时先setlocale(LC_ALL, "")能减少一半这种玄学问题。

3.3 发起连接的参数化命令与结果反馈

连接命令的核心只有一行:

nmcli dev wifi connect "SSID" password "密码"

但代码里最安全的写法是参数列表,不拼字符串:

void WifiConnector::connectTo(const QString &ssid, const QString &password) { QStringList args; args << "dev" << "wifi" << "connect" << ssid; if (!password.isEmpty()) { args << "password" << password; } m_proc->start("nmcli", args); }

QProcess传入包含空格的密码,不需要也不能再加引号。password为空说明可能是开放网络,省略password参数即可。connect命令是同步等待NetworkManager完成关联的,网络不好可能等十秒左右,界面上必须给出“正在连接”的等待状态。nmcli返回“Device 'wlan0' successfully activated”表示成功,非0退出码则表示失败,stderr里带“Error: Connection activation failed”,要把stderr原文显示出来,别只给个“连接失败”。

已保存过的网络不需要再传密码:nmcli dev wifi connect SSID会自动用系统凭据,但旧配置过期时反而会失败。这种场景要先用nmcli connection delete SSID删掉旧配置再连新密码,否则界面会一直报密码错误。连接期间把列表和按钮都disabled,防止用户在等待时又点别的WiFi,触摸屏上重复点击引发的连锁bug很常见。

连接返回后还有IP获取的等待问题。nmcli的connect返回时DHCP可能还没拿到地址,立刻查IP会拿到空。常见做法是等待两秒后执行nmcli -g IP4.ADDRESS dev show wlan0,循环轮询三次、间隔1秒,拿到形如192.168.1.23/24的地址再更新界面。这个延后策略能省掉不少“连上了但界面说没连上”的假故障。

4. 触摸屏弹出软键盘:Qt Virtual Keyboard接入与自绘键盘兜底

4.1 三种软键盘方案对比:虚拟键盘模块、系统键盘、自绘控件

触摸屏上没有物理键盘,软键盘是刚需。三种主流方案边界非常清楚:

方案接入成本手感/定制性平台依赖典型场景
Qt Virtual Keyboard低,pro加模块高,可换布局换皮肤模块要随Qt安装,交叉编译要带上量产设备、纯Qt界面
系统键盘(matchbox-keyboard、onboard、TabTip)极低,QProcess启动低,外观和Qt界面割裂各平台各自有快速原型、演示机
自绘QWidget键盘中,自己排键位最高,完全可控无特殊布局、九宫格、小键盘

Qt Virtual Keyboard对绝大多数场景是最优解:焦点在QLineEdit上时自动弹出,收起跟随焦点,支持布局切换。系统键盘的问题在于它是独立窗口,层级由窗口管理器决定,和Qt界面互相遮挡或抢焦点在轻量级窗口管理器上经常出现,有些嵌入式板子甚至直接跑Qt without WM,系统键盘根本浮不出来。自绘键盘最稳但最费工,要处理焦点事件、按键回填、shift状态、大小写锁定,还得维护一个QWERTY布局。

4.2 Qt Virtual Keyboard的最小接入配置

先确认一个容易翻车的点:Qt 5.15.2 msvc2019_64发行包默认不含Virtual Keyboard模块,Ubuntu上安装Qt时要勾选,或事后用apt装libqt5virtualkeyboard5。嵌入式交叉编译,镜像里也得带上这个模块。

pro文件里加一行:

QT += core gui widgets virtualkeyboard

main.cpp里在创建QApplication前设置输入法模块:

#include <QApplication> #include <QDebug> int main(int argc, char *argv[]) { // 必须在QApplication构造前设置 qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QApplication app(argc, argv); // 触摸屏场景下启用触摸事件合成 app.setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); // 业务代码... return app.exec(); }

设置完这两处,凡是QLineEdit获得焦点,软键盘自动浮出。默认布局是英文;要出中文键盘,pro里加CONFIG += lang-cn或在qmake配置开启。WiFi密码输入场景一般不需要中文候选框,英文布局就够了。如果界面里还有搜索框要给用户输中文,再用中文布局。

qtvirtualkeyboard依赖Qt Quick和QML运行时。Widget工程里加QT += virtualkeyboard会自动拉入Qt Quick相关模块。如果之前禁用了quick模块,这里会报错。跑嵌入式板子时要确认模块编进了镜像里,否则运行时QLineEdit一点就崩溃,这是高频翻车点。排查方法很直接:看Qt安装目录有没有virtualkeyboard的QML目录,没有就回去补装。

4.3 密码输入框的弹出克制与自绘兜底实现

有了Virtual Keyboard,下一步是“克制”:很多设置页不止一个输入框,用户只想点WiFi密码框时弹键盘,结果点其他编辑框也弹出全键盘,体验立刻变差。做法是给QLineEdit安装事件过滤器,只在WiFi密码框的FocusIn里允许输入法启用:

bool WifiPage::eventFilter(QObject *obj, QEvent *e) { if (obj == ui->pwdEdit && e->type() == QEvent::FocusIn) { // 交给输入法模块去弹Virtual Keyboard ui->pwdEdit->setAttribute(Qt::WA_InputMethodEnabled, true); } return QWidget::eventFilter(obj, e); }

如果目标平台实在没有qtvirtualkeyboard,自绘键盘是最后的保险。骨架如下:

class SoftKeyboard : public QWidget { Q_OBJECT public: explicit SoftKeyboard(QWidget *parent = nullptr) : QWidget(parent, Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint) { // Qt::Tool 让键盘不抢焦点且能独立显示在顶层 QGridLayout *lay = new QGridLayout(this); const QStringList keys = {"1","2","3","4","5","6","7","8","9","0", "q","w","e","r","t","y","u","i","o","p", "a","s","d","f","g","h","j","k","l", "Shift","z","x","c","v","b","n","m","Backspace"}; for (const QString &k : keys) { QPushButton *btn = new QPushButton(k, this); lay->addWidget(btn); } setFocusPolicy(Qt::NoFocus); } };

自绘键盘要在按钮点击时把字符回填给当前焦点控件,在构造函数里连接clicked信号并获取QApplication::focusWidget()。设置Qt::Tool时它不抢焦点,主窗口的输入框仍是焦点持有者,这样“点键盘按键”不会把焦点夺走。窗口位置固定屏幕底部,第一版不要做跟随输入框的浮动,先跑通再优化。Windows场景下还有一种省力方案:用QProcess启动TabTip.exe(触摸键盘),路径在C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe,FocusIn时startDetached启动、FocusOut时收起,但外观和Qt界面割裂,一般只用于演示机。

5. 避坑:nmcli权限、密码特殊字符与软键盘遮挡的五个现场

5.1 扫描结果一直为空:先关WiFi开关再谈权限

现象:nmcli dev wifi list命令在终端手工执行正常,Qt程序里QProcess跑同样参数,输出为空或只有“No Wi-Fi device found”。

原因:两种情况最多。一是WiFi射频被关掉了,nmcli radio wifi off状态下扫描命令不报错,但输出空列表。二是NetworkManager服务异常,或者程序跑了但硬件被rfkill锁住。nmcli扫描不需要root,但硬件状态元数据由NetworkManager维护,它服务异常时命令直接返回空。

解决:先查nmcli general status确认NetworkManager running,再用nmcli radio wifi查看射频状态,off则执行nmcli radio wifi on。排查顺序建议:终端手工跑同一条命令确认命令本身没问题;再看PATH里能不能找到nmcli;最后看rfkill锁。嵌入式板子偶发rfkill状态锁定,要写一条“WiFi被RF-Kill阻塞”的日志,不要傻傻显示空白列表。

5.2 SSID带空格和冒号导致解析错位

现象:列表里SSID显示成两截,或连接时拿到的SSID缺了一半。

原因:nmcli -t模式用冒号分隔字段,但SSID本身可以包含冒号。部分版本会自动转义字段内冒号为\:,部分版本不转义,直接split(':')时字段错位。空格不分割字段,但如果解析时按空格二次拆分,也会拆断。

解决:不直接split(':'),先用line.replace("\\:", "%COLON%")把转义冒号替换成占位符,再按冒号切分,切完把占位符还原成冒号。SSID为空时行首会多一个冒号,parts数量会变多,按大小过滤不够,要按“第一个非空字段为SSID、第二个字段可转int为信号强度、第三为加密方式”来校验。这个坑在SSID叫“ABC:Guest”时必现,没有例外。

5.3 密码含$和空格被Shell解释掉

现象:连接命令返回“Error: passphrase must be 8..63 characters”,但密码长度明明够;或连接失败提示密码错误。

原因:QProcess::start带参数列表时不会经过Shell,这是正确做法。但图省事把整个命令拼成一个大字符串再用QProcess::start,系统会交给sh解释,$、空格、引号全被处理一遍。WiFi密码里出现$、!、&很常见,一旦被Shell吃掉就得到错误密码。

解决:永远用QProcess的参数列表形式。字符串拼接这条路一旦走了,转义是无底洞。开发期可以临时把密码明文打日志对照nmcli的报错,确认传进去的值是完整的,再用完即删。老代码改造时,重点检查所有写start("nmcli dev wifi connect...")的地方。

5.4 软键盘不弹或被窗口挡住

现象:Virtual Keyboard在桌面Linux上弹得出来,到嵌入式触摸屏上就不弹了;或者弹出后键盘浮在屏幕中间,把密码框挡得严严实实。

原因:多数嵌入式板子的Qt镜像是精简过的,没有打qtvirtualkeyboard模块;或者窗口系统不含Wayland合成器。弹出的键盘默认靠主窗口定位,全屏应用下主窗口没给键盘预留位置,就会被盖住。

解决:先确认模块是否真实存在。qmlimportscanner能列出实际QML模块,输入qmlimportscanner -rootPath 你的应用目录看有没有VirtualKeyboard。然后在main里设置qputenv("QT_VIRTUALKEYBOARD_HINT", "desktop")或直接指定布局参数。遮挡问题主要靠布局规避:密码输入框放在屏幕上半部分,键盘在底部弹出时自然不遮。

5.5 msvc2019_64的dependent路径报错

现象:Windows上用VS2022打开Qt工程,编译一开始就报:-1: error: dependent '..\..\..\..\..\..\qt\5.15.2\msvc2019_64\include\qtwid...' does not exist这类错误,整个工程没法编译。

原因:这不是代码问题,是.pro里QT模块名写错或内置了错误的Qt版本路径。qmake生成Makefile时把QT +=的模块名映射到安装路径,模块名不存在时生成一个不存在的dependent路径,编译一步都走不下去。

解决:先检查.pro文件的QT +=行,widgets模块就是widgets,不是qtwidgets。再确认Qt Kit选的是5.15.2 msvc2019_64而不是MinGW或32位版本。改完后删除构建目录里所有Makefile重新qmake,必要时先“Run qmake”再“Rebuild All”。这种错在拷贝别人工程时特别多,本质是缓存问题,我的习惯是直接清掉shadow build目录去猜路径。Windows下切换编译器时还要注意依赖库也得分版本,5.15.2 msvc2019_64和MinGW混用会让链接错误多到怀疑人生。

6. 把连接做得再稳一点:自动重连、DHCP等待与开机自启

到了这个阶段,扫描、显示、连接、软键盘都通了,但现场连续跑三天后你会有几个额外需求:设备重启后能不能自动连上已保存的WiFi?信号变差时界面和状态能不能跟上?客户环境是园区网,连上WiFi还要过Portal认证,此时界面怎么引导?这三件事决定了功能从“能演示”走向“能交付”。

自动重连:NetworkManager本身有autoconnect机制,nmcli con mod SSID connection.autoconnect yes可以开启,但状态反馈到Qt界面还是要自己轮询。我一般把连接成功的SSID和密码写进QSettings,程序启动时先nmcli con up SSID,失败再用保存的密码走一遍连接流程。轮询用QTimer每3秒跑一次nmcli -t -f GENERAL.STATE,IP4.ADDRESS dev show wlan0,状态变化时发信号更新标题栏图标。别用500ms刷新,高频轮询会把自己带进坑里,NetworkManager也会限频。

DHCP等待:之前提过连接返回后立刻查IP是空的。正确顺序是“连接成功 → 等状态变成connected → 再等1~2秒查IP4.ADDRESS → 界面显示IP”。IP一直拿不到,多数是网段不对、Portal拦截或DHCP池满,界面要明确提示“IP获取失败”,而不是让客户以为连上了就万事大吉。这部分逻辑不复杂,但一定要在真机上抓一份日志确认再写死。

开机自启:工控设备用systemd托管Qt程序,但NetworkManager开机后0~5秒才完成扫描,程序启动太早会扫到空的WiFi列表。systemd unit里加After=network-manager.service,程序里做启动后3秒延时的延迟扫描,就能规避。Debian精简镜像还要确认nmcli命令在服务进程的PATH里可执行,路径要写完整。

最后说一个我的习惯:做这套功能时,先到开发板的Shell里把每条命令执行一遍、记录输出格式,再回Qt代码里照抄解析。nmcli的版本差异坑过我很多次,不同发行版对“已连接”标记的位置都有变化。曾经有同事直接照抄另一套代码的解析逻辑,上线两天搜不到热点,一查是版本号不同输出格式全变了。经过那一次之后,我的自查清单里永远有一条:在目标机器上先运行nmcli --version和完整命令输出,确认字段结构后再写解析。这也是最有效的后悔药,省下的大把排查时间远远超过写解析那几分钟。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 18:28:21

VoiceStudio:开源语音操作系统架构与工程实践指南

1. VoiceStudio不是又一个“AI配音工具”&#xff0c;而是开源语音工作流的底层操作系统最近在几个技术社区和创作者群里&#xff0c;频繁看到有人发截图问&#xff1a;“这个VoiceStudio到底是什么&#xff1f;GitHub star涨得比Vite还快&#xff0c;但文档里全是英文&#xf…

作者头像 李华
网站建设 2026/10/30 18:19:49

C语言格式化缓冲区池被单次printf调用耗尽的原因与改法

问题现象 C 语言里没有类,想给自定义类型做统一的字符串化,常见做法是给每个类型写一个 fmt_<type>() 函数,内部用一块共享缓冲区格式化后返回指针。为了让多个返回值能同时出现在一次 printf 里,往往会做一个缓冲区池: #include <stdio.h>#define COUNT_OF…

作者头像 李华
网站建设 2026/10/30 17:25:08

大模型系统性入门:从硬件到评估的完整知识骨架

1. 这不是“速成课”&#xff0c;而是一张大模型世界的地形图你搜“大模型入门”&#xff0c;页面上扑面而来的是&#xff1a;3天学会LLM、零基础玩转ChatGLM、保姆级部署Llama3教程……点开一看&#xff0c;要么是调用一个API接口就宣告“已掌握”&#xff0c;要么是复制粘贴几…

作者头像 李华
网站建设 2026/10/30 17:14:55

SpringBoot校园二手交易平台毕设源码部署与避坑指南

简介&#xff1a;基于SpringBoot的校园二手交易平台系统源码与数据库脚本&#xff08;毕业设计&#xff09;项目&#xff0c;面向计算机相关专业毕业生及Java学习者&#xff0c;可用于毕业设计、课程设计或期末大作业。系统前端涉及产品分类、产品明细、用户注册、产品公告、在…

作者头像 李华
网站建设 2026/10/30 17:14:48

SpringBoot垃圾分类识别小程序:架构设计、数据库与部署全流程

简介&#xff1a;一套面向毕业设计场景的垃圾分类识别小程序项目源码&#xff0c;基于SpringBoot框架构建&#xff0c;后端使用Java语言实现&#xff0c;并附带数据库脚本与部署说明&#xff0c;整体覆盖从后台服务到小程序前端展示的完整闭环流程。项目定位清晰&#xff0c;适…

作者头像 李华