HOWTO · Arduino
Arduino `memset()` 函数
了解如何在 Arduino 中用 `memset()` 重复填充指定字节范围,以及何时应改用类型赋值。
本页内容
memset() 会从目标地址开始,用同一个字节值填充指定数量的字节。要计算数组所需的字节数,可以使用 sizeof;如果要把数值赋给数组中的每个元素,则应使用类型赋值。
Arduino 中的 memset() 函数简介
在 Arduino C++ 中,memset() 用一个重复的字节值填充连续的字节范围。它适用于字节缓冲区和字符数组,但不会把一个多字节数值复制到每个元素中。第三个参数表示字节数,因此应根据实际要填充的存储空间来计算。
标准函数声明在 <string.h> 中,也可通过 C++ 头文件 <cstring> 使用。调用形式为 memset(destination, value, byte_count):destination 指向起始字节,value 会转换为一个无符号字节,byte_count 指定要写入的字节数。函数会重复这个转换后的字节,不会从原始数值中逐字节取值。
在 Arduino 中使用 memset()
下面这个完整的 C++ 示例会填充一个字符数组,然后修改其中一段范围。示例使用标准输出,因此无需连接特定开发板或使用其串口即可演示字节操作。
#include <cstring>
#include <iostream>
int main() {
char letters[] = "hello";
std::memset(letters, '.', sizeof(letters) - 1);
std::memset(letters + 1, 'a', 2);
std::cout << letters << '\n';
return 0;
}
.aa..
这个数组可以容纳五个字母以及结尾的空字符。第一次调用只填充五个可见字符所占的字节,保留结尾空字符;第二次从索引 1 开始写入两个字节,因此会修改索引 1 和 2 处的字符。在 Arduino 草图中也可以对同样的数组执行这些 memset() 操作;若要显示结果,可使用 Serial.print()。
对于元素类型不同的数组,应从数组本身计算字节数。例如,memset(values, 0, sizeof(values)) 会填充 values 中的每个字节。若要填充一段完整元素,则先按元素数量移动起始位置,再将元素数量乘以单个元素的字节数:memset(values + start, byte_value, count * sizeof(values[0]))。数组索引从零开始,所选范围必须完全落在数组的存储空间内。
用字节值 2 填充整数数组,并不等于给每个元素赋整数值 2。在 int 为 16 位且采用小端表示的目标平台上,每两个字节会变成 0x0202,对应的数值是 514。其他整数宽度或表示方式可能得到不同结果。如果目的是将整数值 2 赋给每个元素,应使用循环,例如 for (int i = 0; i < count; ++i) values[i] = 2;。
若要修改 Arduino String 中的字符,可以通过索引直接赋值,例如 text[i] = '.';。这是直接的字符赋值,并没有使用 memset()。
重要注意事项
务必确认目标指向可写存储空间,并且字节数没有超出该空间的范围。对于数组,只有当表达式仍指向数组本身时,sizeof(array) 才会给出数组的总字节数;如果函数参数声明为数组,它实际是一个指针,因此必须另外传入或计算数组长度。字节数为零时不会写入任何字节,但按照该函数的约定,目标仍必须是有效指针。
重复字节模式并不是通用的对象赋值方式。只有确实需要该字节级表示时才适合使用,例如填充字符缓冲区或清零字节。不要用它初始化非平凡 C++ 对象,包括管理资源或依赖构造函数与内部不变条件的对象。对于普通数值和对象,应使用类型赋值、值初始化或对象自身提供的接口。
总结
当需要用一个字节重复填充已知范围时,使用 memset()。按字节计算范围;处理数组时,要考虑元素宽度,并确保写入始终位于目标存储空间内。对于整数、字符串和对象,除非确实需要重复的字节模式,否则应优先使用类型赋值或合适的初始化方式。