编译器内建函数实战:用位运算与溢出检测优化C/C++性能

优化性能的时候,我把手写的位运算、溢出判断、分支预测代码一一换成了编译器内建函数(built-in functions / intrinsics)之后,生成出来的目标代码明显更干净,有些场景甚至少了好几条指令。这篇就集中聊聊编译器内建函数的使用:它解决什么问题、哪些场景收益最大、用的时候有哪些坑,以及怎么验证它真的生效了。

适合谁看:正在做C/C++底层优化、嵌入式代码、解析器或图像/音视频处理的朋友;如果你写业务代码但对“编译器为什么能优化得这么聪明”有好奇,也能从里面获得一些直观认识。我不会把每个编译器的内建函数都罗列一遍,而是挑实用频率最高、收益最明显的一组,配合可复现的代码和排查思路来讲。

1. 为什么需要编译器内建函数

1.1 从内联汇编到内建函数:底层优化的思路演变

早年做底层优化,绕不开内联汇编。想数一个整数有多少个1,直接写BSF、POPCNT这样的指令;想做溢出判断,直接读标志寄存器。但内联汇编有几个很现实的问题:

  • 不同CPU架构的指令差异太大,一套汇编只能在一种架构上用,代码基本没法移植。
  • 内联汇编块在编译器眼里是“黑盒”,它会妨碍寄存器分配、指令调度、常量传播等优化。GCC还经常因为asm的clobber约束没写对,导致生成比你想象的还差的代码。
  • 维护成本高。过几个月回来看一堆汇编,阅读理解全靠注释,而注释往往已经过时了。

编译器内建函数就是在这背景下出现的:它长得像函数调用,但编译器在语义分析阶段就认识它,直接把它翻译成合适的指令序列或参与更高层的优化决策。你写__builtin_popcount(x),在支持POPCNT指令的目标上可能生成一条popcnt,在不支持的老CPU上可能生成一段无分支位运算。你不需要关心底层实现,编译器帮你选。

1.2 内建函数和普通库函数的本质区别

普通库函数是有实体的,你调用memcpy,最终链接的是某个库里的实现(虽然编译器也常常优化内联它)。内建函数通常没有实体,你不能对它取地址,也不应该期望它出现在符号表里。它在编译期就“消失”了,变成指令或优化决策。

这个区别带来一个关键点:内建函数的使用要像“告诉编译器一个事实”一样,而不是“调用一个功能模块”。举个例子,__builtin_expect(cond, 1)的意思是“我判断cond大概率成立,请你按这个信息优化分支布局”,它本身不改变程序的运行结果,只是给出了一条额外信息。所以写的时候要把思考方式从“调用什么函数”切换成“给编译器提供什么语义约束”。

1.3 哪些人最能从中受益

我列了三类典型场景:

  • 系统级与嵌入式的关键路径代码:比如中断处理、网络协议栈、序列化反序列化,这些代码对分支预测、溢出检测的真实性、指令数都非常敏感。
  • 高性能计算和媒体处理:SIMD代码里,对齐假设、popcount、前导零/尾部零这些操作高频出现。手写版容易出错,内建函数版本既安全又清晰。
  • 通用业务代码里的“性能意外”:很多人不知道有符号整数溢出在C/C++里是未定义行为,也不知道编译器会基于“不会溢出”这个假设做优化。用内建溢出检测函数可以一举两得:既避免UB,又省下手写判断逻辑。

2. 核心内建函数逐个拆解

2.1 分支预测:__builtin_expect与现代写法的关系

__builtin_expect(expr, expected)告诉编译器哪个分支更可能被执行。比如在解析器里,检查“当前字符是否是白名单字符”是一个高频且大多为真的分支:

if (__builtin_expect(is_regular_char(ch), 1)) { process(ch); } else { handle_special_char(ch); }

编译器会据此调整生成的汇编布局,把“大可能走的路径”放在顺序执行路径上,减少跳转。很多人以为它影响CPU的分支预测器,其实不对。它主要影响的是编译器生成的代码布局和内存布局,让流水线不容易因为跳转而flush。

现代C++20里有了标准属性[[likely]]和[[unlikely]],GCC/Clang内部往往就把它们映射到__builtin_expect上。但存量项目大多还是C代码,或者还在用C++11/14,此时__builtin_expect依然是主力。

注意:__builtin_expect的第一个参数会被当成布尔表达式,建议写成!!(x)把指针、整数等统一转成0/1,避免和复杂的条件表达式混合时出现类型相关警告。

2.2 数学运算溢出检测:__builtin_add_overflow 系列

这类函数是GCC/Clang自带的一组内建函数:

__builtin_add_overflow(a, b, &res) __builtin_sub_overflow(a, b, &res) __builtin_mul_overflow(a, b, &res)

返回值是int类型,1表示溢出,0表示正常;计算结果会写到res指针指向的变量。注意:即使溢出,res里也会被写入按相应宽度截断后的结果。

有符号整数溢出是未定义行为,这是个很多老手都踩过的经典坑。以前我们手写安全加法,思路是先用减法判断边界再相加:

int safe_add_manual(int a, int b, int *res) { if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) { return -1; } *res = a + b; return 0; }

这段逻辑对不对?对。但你为每种类型组合都要写一遍,代码膨胀不说,稍不留神把INT_MIN写成INT_MAX就出大问题。换成内建函数:

if (__builtin_add_overflow(a, b, &res)) { return -1; }

它在支持标志寄存器的架构上,通常生成一条add指令加上一条条件跳转或seto,直接在硬件层面完成溢出检测,没有额外的边界比较指令。对无符号类型,溢出检测也有用,比如计算长度、哈希、内存偏移时想确认“回绕”没有发生。

2.3 位运算三件套:clz、ctz、popcount

这三个函数在算法题、数据压缩、内存分配器、哈希表里出镜率极高:

  • __builtin_clz(x):统计前导0的个数,x不能为0,否则结果未定义,调用前得先判断。
  • __builtin_ctz(x):统计尾部0的个数,x同样不能为0。
  • __builtin_popcount(x):统计二进制里1的个数,x为0是安全的,结果为0。

它们按unsigned int设计,有相应的长整型变体:__builtin_clzl、__builtin_clzll、__builtin_ctzll、__builtin_popcountll。在x86平台上,clz可能对应lzcnt或bsr指令(看CPU是否支持LZCNT),ctz对应tzcnt或bsf,popcount对应popcnt指令,也看编译选项和目标CPU。在不支持这些指令的老架构上,编译器会展开成位运算序列,你依然不用自己写。

2.4 给优化器的“事实声明”:__builtin_assume_aligned 与 __builtin_unreachable

__builtin_assume_aligned(ptr, alignment)用来声明一个指针满足对齐要求。我的手写SIMD代码里很需要它,因为很多向量化加载指令要求地址对齐,比如16字节、32字节、64字节。把用aligned_alloc分配好的指针传给这个内建函数,然后代码里对结果做强制类型转换和向量化,编译器就可以直接使用对齐访问指令,并且更激进地做循环向量化。

__builtin_unreachable()则是一个更强的声明:告诉编译器当前控制流路径永不抵达。典型场景是switch的default分支,当你确定入参的枚举值范围时:

switch (type) { case TYPE_A: return handle_a(); case TYPE_B: return handle_b(); default: __builtin_unreachable(); }

它可以让编译器删除后续防御性的边界检查,生成更紧凑的代码。但代价是:如果运行时机误到达了声明不可达的位置,程序进入未定义行为,可能比普通崩溃更诡异。所以在Debug版本尽量避免依赖它,或者配合断言一起使用。

2.5 编译器支持矩阵与可移植性

内建函数GCC/ClangMSVC说明
__builtin_expect支持不支持MSVC可用__assume替代,但语义有差别
__builtin_add_overflow支持无直接对应MSVC可用SafeInt库或自写边界判断
__builtin_clz/ctz/popcount支持无同名函数MSVC对应_BitScanForward/_BitScanReverse/__popcnt
__builtin_assume_aligned支持无直接对应MSVC用__assume声明,但不对指定对齐做向量化优化
__builtin_unreachable支持支持MSVC也有__assume(0),语义相近

我建议做法是封装宏,比如:

#if defined(__GNUC__) || defined(__clang__) #define LIKELY(x) __builtin_expect(!!(x), 1) #define UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define LIKELY(x) (x) #define UNLIKELY(x) (x) #endif

这样业务代码里不直接出现编译器特有的名字,换编译器或做实验时改一个头文件就行。

3. 实操演示:三个案例看清内建函数的边界和收益

3.1 案例一:popcount——查表法、手写位运算、内建函数

我拿一个统计“位图里已使用bit数”的常见需求举例。先看查表法:

static unsigned char table[256] = {0,1,1,2,1,2,2,3, /* ... */}; int count_table(const unsigned char *data, size_t len) { int total = 0; for (size_t i = 0; i < len; i++) total += table[data[i]]; return total; }

然后是手写分治位运算,典型代码长这样:

int count_manual(unsigned int x) { x = x - ((x >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x + (x >> 4)) & 0x0f0f0f0f; x = x + (x >> 8) + (x >> 16); return x & 0x7f; }

这段代码在很多经典书里出现,但它有两个问题:第一,不写注释的话大多数人都看不懂;第二,不同编译器对它的指令选择差异很大,有时候生成效果的优劣要试了才知道。

换成内建函数:

int count_builtin(unsigned int x) { return __builtin_popcount(x); }

在x86平台且开启了-mpopcnt或-march=native时,它可能生成单条popcnt指令。在没开启相关选项时,GCC/Clang通常也会生成一段无分支的位运算序列,代码质量和你精心手写版相差不大,但可读性好得多。实际项目中我会优先选择内建函数,只有在确认目标CPU不支持POPCNT且无法使用运行时指令检测时,才考虑查表法。

3.2 案例二:有符号整数溢出安全加法——为什么手写判断很危险

假设你要实现一个带校验的长度计算,原来的代码是这样:

int old_calc(int base, int delta, int *out) { int result = base + delta; // 溢出是UB,编译器可能做奇怪优化 if (result < 0) return -1; *out = result; return 0; }

这段代码有UB。更危险的是,某些编译器在开启了高层优化后,会把“result < 0这个分支永远不成立”当作事实来用,因为UB对你程序是允许被假设为不会发生的。结果就是你的安全检查在生成代码里被删除,变成一个完全没防护的加法。这不是段子,实操中真的会出现。

改成内建函数版本:

int safe_calc(int base, int delta, int *out) { if (__builtin_add_overflow(base, delta, out)) { return -1; } return 0; }

在x86-64上,这段代码一般会生成类似如下的指令模式(伪汇编):

add %esi, %edi jo .overflow mov %edi, (%rdx) xor %eax, %eax ret

也就是一条加法指令,然后直接利用溢出标志跳转。没有边界比较、没有额外分支判断,性能和安全性同时拿到手。我之前在某个跨平台系统里维护过同类逻辑,替换后用反汇编工具确认过,代码量减少三分之一左右,行为完全一致。

3.3 案例三:热路径上的分支优化——expect如何改变代码布局

再说一个解析器场景。我在某图像处理Demo里处理自定义格式的头字段,每个字段类型是一个枚举值,大多数情况下是普通数据块。原来是:

if (field->type == FIELD_DATA) { parse_data(field); } else if (field->type == FIELD_PADDING) { skip_padding(field); } else { parse_special(field); }

实际统计中,FIELD_DATA占比可能超过95%,但编译器不知道。给它加一条内建函数提示:

if (__builtin_expect(field->type == FIELD_DATA, 1)) { parse_data(field); } else if (__builtin_expect(field->type == FIELD_PADDING, 0)) { skip_padding(field); } else { parse_special(field); }

这个改动对运行结果没有任何影响,但它可能改变汇编里基本块的排列顺序:把高频路径串在一起,让低频错误处理分支跳到函数末尾。对于几十万次迭代的解析循环,分支预测失败和指令缓存的压力都会降低。实测下来大多数场景有5%到15%的收益,具体看循环体积和分支密度。不要把它当成万能特效药,但它确实是一项值得加在关键分支上的低成本优化。

4. 实战中的常见坑与排查思路

4.1 坑1:把内建函数当“万能加速器”

内建函数不会自动让算法变快。如果算法本身是O(n^2),把循环里的popcount换成内建函数也救不回来。它的作用边界是“在特定操作上减少指令数”或“为优化器提供更清晰的语义”,而不是“整体性能提升”。我做过的实测里,__builtin_expect用在不规律的分支场景上,效果可以忽略甚至略差;因为现代CPU有很强大的动态分支预测器,编译器只有关于概率的静态提示,如果实际分布和提示不一致,反而会导致布局恶化。所以先明确热点在哪里,再考虑是否使用。

4.2 坑2:假设内建函数必然生成你想要的指令

很多人以为写完__builtin_popcount就一定会生成popcnt指令。这不完全对。假设你编译老CPU目标,编译器可能生成位运算序列;假设目标CPU支持该指令但你没开对应选项,GCC也不一定会用。正确做法是:用反汇编确认。而且像__builtin_clz在x86上有时生成bsr配合异或,有时生成lzcnt,不同CPU指令长度和语义都有差别。不要以“感觉”为准,要以实际生成的汇编为准。

遇到必须运行在旧CPU上的情况,比如某些嵌入式平台,可以用__builtin_cpu_supports这类运行时能力判断来分流:检测到支持就用内建函数对应指令,不支持就走通用位运算路径。有的编译器还提供__builtin_cpu_init需要先在main里调用,这细节很容易被忽略。

4.3 坑3:在MSVC或其他编译器上直接照搬

GCC和Clang的内建函数命名习惯相似,但MSVC是另一套体系。MSVC的位扫描函数是_BitScanForward、_BitScanReverse,popcount是__popcnt,分支提示是__assume,语义和用法都不完全一样。如果你在写跨编译器代码,直接写__builtin_expect会编译不过。前面说的宏封装方案是稳妥做法,把差异收敛到一个头文件里。

更隐蔽的问题是:一些内建函数在不同编译器上对参数类型的要求不同,比如__builtin_clz的参数宽度、无符号性有约束,混用可能导致未定义行为或警告。我在一次重构里遇到过__builtin_clz传入long类型、同事期望统计64位的前导零,结果实际上只统计到低32位,数据量一大结果就错。解决办法是明确使用带ll后缀的变体,并加类型检查。

4.4 坑4:__builtin_assume_aligned 和 __builtin_unreachable 的错误使用

对齐假设是双刃剑。曾经有个优化任务,我对某跨平台系统的图像缓冲区做了__builtin_assume_aligned(ptr, 64),自信满满地让编译器做64字节宽度的向量化。结果只在某个平台崩溃:因为那块缓冲区来自旧接口,实际只保证16字节对齐。编译器按照我的假设生成了对齐vmovdqa指令,一遇到非对齐地址就异常。排查了很长时间才定位。这个教训是:每次使用对齐假设前,必须确认数据来源的真实对齐属性,不要在普通指针上想当然。

__builtin_unreachable也一样危险。它和断言不同,断言在Debug下还能被发现,而未定义行为的爆发点往往很奇怪。我记得有次在某图像处理Demo里把统一入口的default分支标记为不可达,结果某次重构后一个新的枚举值进入这个入口,编译器基于不可达的特性做了分支删除,最终现象是数据被静默忽略,完全不报错。后来我改成:Debug构建用assert(0),Release构建用__builtin_unreachable(),至少开发阶段能暴露问题。

4.5 实用的排查与验证方法

验证一个内建函数是否生效,我通常按这四步走:

  1. 把最小复现代码单独提出来,用目标编译器的选项编译,生成汇编文件。比如GCC加-S -O2,再看输出里是否有预期指令。
  2. 用宏封装来做A/B对比。同样一份业务逻辑,一组用内建函数,一组用普通写法,在反汇编窗口逐个对比指令差异。
  3. 做基准测试时,不要只看“单次执行时间”,观察分支预测失败次数、缓存未命中次数。用性能剖析工具或芯片自带的计数器,能发现单纯看时间看不出来的变化。
  4. 加编译警告选项,比如-Wall -Wextra。很多内建函数用错类型时,编译警告会立刻提示;别把警告淹死在日志里。

这套方法我几乎每次优化都用,能避免“以为优化了、实际负优化”的情况。特别是涉及__builtin_assume_aligned这种“事实声明”型内建函数时,反汇编和运行时验证缺一不可。

5. 一点个人体会

关于编译器内建函数,我越来越觉得它像是“和编译器谈判”:你付出一段清晰的语义声明,编译器还给你更优的代码生成。它不是银弹,但如果用对地方,能够在保持代码可读性的前提下拿到接近手写汇编的效果。我的习惯是:先把内建函数封装成可开关的宏或内联函数,保证业务代码里看不到编译器特有的魔法;然后再在确认真实热点的路径上逐个替换,用反汇编和基准测试确认收益。这样既稳又快,遇到问题还能一键回退。如果你还没试过,建议下个项目里挑一个热点分支或一个溢出检测点,先把它换成内建函数,看看生成的汇编是不是变干净了。

相关新闻

Vite 7.0 现代化 WebAssembly(Wasm)极速构建流水线:基于 Rust 原生集成

Vite 7.0 现代化 WebAssembly(Wasm)极速构建流水线:基于 Rust 原生集成

上周四晚上&#xff0c;我正在给我的出海数字隐私小工具——一个运行在浏览器本地的“离线 PDF 敏感信息脱敏与图像无损压缩器”修 Bug。凌晨一点&#xff0c;我家橘猫 Bug 正把胖乎乎的大脸严严实实地堵在我的机械键盘方向键上&#xff0c;喉咙里发出拖拉机般的咕噜声。而我的…

2026/10/20 22:05:24 阅读更多 →
程序员转型AI系统设计:从模型到高并发推理服务的补课路线

程序员转型AI系统设计:从模型到高并发推理服务的补课路线

1. 为什么程序员转型AI系统设计总踩坑1.1 一个普遍存在的认知错位我接触过不少做后端、前端甚至嵌入式开发的朋友&#xff0c;这两年都在往AI方向靠。大家的路径出奇地一致&#xff1a;先花两周啃完某门机器学习入门课&#xff0c;再跑几个开源模型Demo&#xff0c;然后就开始投…

2026/10/20 22:05:24 阅读更多 →
Python文档批量处理实战:格式转换、文本清洗与办公自动化

Python文档批量处理实战:格式转换、文本清洗与办公自动化

拿文档处理说事儿&#xff0c;很多人第一反应是&#xff1a;这还不简单&#xff0c;打开文件&#xff0c;复制粘贴&#xff0c;另存为&#xff0c;完事儿。真到手上批量处理几十个、上百个文件时&#xff0c;你很快会发现&#xff0c;事情完全不是想象中那样。编码乱码、标题格…

2026/10/20 22:05:24 阅读更多 →

最新新闻

博科48000交换机安装维护实战指南:端口规划与Zoning配置

博科48000交换机安装维护实战指南:端口规划与Zoning配置

简介&#xff1a;本资源是博科&#xff08;Brocade&#xff09;光纤通道SAN交换机的官方级安装与维护实操手册&#xff0c;面向企业IT运维工程师、存储网络架构师及SAN系统实施人员&#xff0c;聚焦FC-SAN环境下的设备部署、冗余规划、微码升级与日常维护等核心运维场景。文档共…

2026/10/21 0:10:20 阅读更多 →
Java对接支付宝对账单下载接口:从调用到解析入库的完整实践

Java对接支付宝对账单下载接口:从调用到解析入库的完整实践

1. 对账单下载这件事&#xff0c;为什么值得单独拎出来讲做过支付对接的人都有一个共识&#xff1a;支付主链路&#xff08;下单、支付、回调&#xff09;反而是最简单的部分&#xff0c;真正让人头疼的是对账。下单支付是实时链路&#xff0c;出了问题用户马上就能反馈&#x…

2026/10/21 0:10:20 阅读更多 →
SpringBoot+Vue+MySQL社区流浪动物救助系统开发全解析

SpringBoot+Vue+MySQL社区流浪动物救助系统开发全解析

简介&#xff1a;这是一套基于Java、SpringBoot、Vue与MySQL实现的社区流浪动物救助系统完整毕业设计项目&#xff0c;面向计算机相关专业学生&#xff0c;适用于毕业设计、课程设计或期末大作业。系统后端采用SpringBoot框架&#xff0c;前端使用Vue.js&#xff0c;数据库脚本…

2026/10/21 0:10:20 阅读更多 →
STM32寄存器白话手册:从硬件开关视角理解位操作

STM32寄存器白话手册:从硬件开关视角理解位操作

1. 为什么“寄存器手册”从来不是一本能直接读完的书&#xff1f;刚接触STM32那会儿&#xff0c;我桌上常年摊着三份文档&#xff1a;ST官方的《Reference Manual》&#xff08;RM&#xff09;、《Datasheet》&#xff08;DS&#xff09;&#xff0c;还有一本被翻得卷了边的《C…

2026/10/21 0:10:20 阅读更多 →
STM32+华为云IoT+Qt智能家居跨平台实战:低功耗、高可靠、真可用

STM32+华为云IoT+Qt智能家居跨平台实战:低功耗、高可靠、真可用

1. 这套系统到底在解决什么真实问题&#xff1f;——从“能连上”到“真好用”的断层很多人第一次听说“STM32华为云IoTQt”这个组合时&#xff0c;第一反应是&#xff1a;又一个技术堆砌的Demo&#xff1f;确实&#xff0c;网上太多项目只停留在“LED灯亮了”“温湿度数据上云…

2026/10/21 0:10:20 阅读更多 →
ADC采样精度与取平均实战:从原理到配置的避坑指南

ADC采样精度与取平均实战:从原理到配置的避坑指南

ADC 这个模块&#xff0c;说起来简单&#xff0c;做起来坑多。很多人第一次接触模数转换&#xff0c;觉得不就是把模拟电压读进来变成数字嘛&#xff0c;配置一下寄存器、开个通道、读个值就完事了。但真正到了项目里&#xff0c;你会发现读回来的数跳得厉害、精度对不上、采样…

2026/10/21 0:09:19 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事&#xff1a;AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里&#xff0c;按宣传口径&#xff0c;本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”&#xff0c;而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起&#xff1a;用户到底在追求什么“封号重开”这四个字&#xff0c;放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流&#xff0c;背后是大量的时间和精力成本。正常情况下&#xff0c;没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”&#xff0c;而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时&#xff0c;就意识到&#xff1a;单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →