嵌入式Linux开发实用代码片段与优化技巧

张开发
2026/4/15 17:02:39 15 分钟阅读

分享文章

嵌入式Linux开发实用代码片段与优化技巧
1. 实用代码片段分享提升开发效率的小工具作为一名嵌入式开发者我经常需要处理各种系统级操作。今天分享几个我在实际项目中积累的实用代码片段这些代码虽然短小但能解决很多常见问题。这些代码主要针对Linux系统环境使用C语言实现涵盖了系统信息获取、文件操作等常见需求。2. 核心代码片段解析2.1 获取CPU温度在嵌入式系统监控和性能分析中获取CPU温度是一个常见需求。特别是在长时间运行的设备上温度监控尤为重要。#include stdio.h #include unistd.h #include stdlib.h #include string.h #include errno.h #define CPU_TEMP_FILE0 /sys/devices/virtual/thermal/thermal_zone0/temp struct cpu_temperature { int integer_part; int decimal_part; }; typedef struct cpu_temperature cpu_temperature_t; cpu_temperature_t get_cpu_temperature(const char *_cpu_temp_file) { FILE *fp NULL; cpu_temperature_t cpu_temperature {0}; int temp 0; fp fopen(_cpu_temp_file, r); if (NULL fp) { printf(fopen file error\n); return cpu_temperature; } fscanf(fp, %d, temp); cpu_temperature.integer_part temp / 1000; cpu_temperature.decimal_part temp % 1000 / 100; fclose(fp); return cpu_temperature; } int main(int arc, char *argv[]) { cpu_temperature_t cpu_temperature {0}; cpu_temperature get_cpu_temperature(CPU_TEMP_FILE0); printf(cpu_temperature %d.%d ℃\n, cpu_temperature.integer_part, cpu_temperature.decimal_part); return 0; }实现原理 Linux系统通过虚拟文件系统暴露硬件信息CPU温度通常存储在/sys/devices/virtual/thermal/thermal_zone*/temp文件中。该文件包含一个整数值表示温度单位为毫摄氏度。注意事项不同Linux发行版或硬件平台温度文件路径可能不同某些系统可能有多个thermal_zone对应不同温度传感器读取频率不宜过高避免频繁文件IO影响系统性能扩展应用可以封装为守护进程定期记录温度变化结合阈值判断实现过热保护机制与系统日志集成便于问题排查2.2 获取文件大小文件操作是开发中的常见需求获取文件大小是很多文件操作的前提条件。#include sys/stat.h #include unistd.h #include stdio.h long get_file_size(const char *_file_name) { FILE * fp fopen(_file_name, r); if (NULL fp) { printf(fopen error\n); return -1; } fseek(fp, 0L, SEEK_END); long size ftell(fp); fclose(fp); return size; } int main() { #define FILE_NAME ./get_file_size long file_size get_file_size(FILE_NAME); printf(file_size %ld\n, file_size); return 0; }实现原理 通过fseek将文件指针移动到文件末尾然后使用ftell获取当前位置偏移量即文件大小。替代方案 也可以使用stat系统调用struct stat st; stat(filename, st); size st.st_size;注意事项对于大文件超过2GB需要使用fseeko和ftello替代文件路径需要确保有访问权限返回-1表示出错需要检查errno确定具体原因2.3 获取高精度时间戳精确计时是性能分析和事件排序的基础系统时间戳在很多场景都非常有用。#include stdio.h #include unistd.h #include stdlib.h #include string.h #include errno.h #include sys/time.h #include time.h long long get_sys_time_ms(void) { long long time_ms 0; struct timeval sys_current_time; gettimeofday(sys_current_time, NULL); time_ms ((long long)sys_current_time.tv_sec*1000000 sys_current_time.tv_usec) / 1000; return time_ms; } int main(int arc, char *argv[]) { long long cur_sys_time get_sys_time_ms(); printf(cur_sys_time %lld ms\n, cur_sys_time); return 0; }实现原理gettimeofday系统调用提供微秒级精度的时间获取通过组合秒和微秒部分计算毫秒时间戳。注意事项在多线程环境中需要考虑性能影响系统时间可能被修改不适合作为唯一时序依据对于更高精度需求可以考虑clock_gettime和CLOCK_MONOTONIC扩展应用性能分析计算代码段执行时间事件排序为日志添加精确时间戳超时控制实现精确的定时机制2.4 获取网络接口MAC地址MAC地址作为网络设备的唯一标识在很多场景都有应用价值。#include stdio.h #include net/if.h #include sys/ioctl.h #include arpa/inet.h #include unistd.h #include string.h int get_netif_mac(const char *_ifr_name, uint8_t *_mac) { int32_t ret -1; struct ifreq m_ifreq; int32_t sock 0; sock socket(AF_INET, SOCK_STREAM, 0); if (sock 0) { printf(socket err\n); goto err; } strcpy(m_ifreq.ifr_name, _ifr_name); ret ioctl(sock, SIOCGIFHWADDR, m_ifreq); if (ret 0) { printf(ioctl err:%d\n,ret); goto err; } snprintf((char *)_mac, 32, %02x%02x%02x%02x%02x%02x, (uint8_t)m_ifreq.ifr_hwaddr.sa_data[0], (uint8_t)m_ifreq.ifr_hwaddr.sa_data[1], (uint8_t)m_ifreq.ifr_hwaddr.sa_data[2], (uint8_t)m_ifreq.ifr_hwaddr.sa_data[3], (uint8_t)m_ifreq.ifr_hwaddr.sa_data[4], (uint8_t)m_ifreq.ifr_hwaddr.sa_data[5]); return 0; err: return -1; } int main(int argc, char **argv) { char mac_str[32] {0}; get_netif_mac(wlan1, mac_str); printf(mac %s\n, mac_str); return 0; }实现原理 通过ioctl系统调用和SIOCGIFHWADDR命令获取网络接口的硬件地址。注意事项需要root权限或CAP_NET_ADMIN能力不同网络接口名称需要适配eth0, wlan0等虚拟接口可能返回全零或随机MAC扩展应用设备唯一标识生成网络权限控制设备合法性验证2.5 获取网络接口IP地址获取本地IP地址是网络编程中的常见需求特别是在需要显示或配置网络信息的场景。#include stdio.h #include net/if.h #include sys/ioctl.h #include arpa/inet.h #include unistd.h #include string.h int get_local_ip(const char *_ifr_name, char *_ip) { int ret -1; int sockfd; struct sockaddr_in sin; struct ifreq ifr; sockfd socket(AF_INET, SOCK_DGRAM, 0); if (-1 sockfd) { printf(socket error\n); return ret; } strncpy(ifr.ifr_name, _ifr_name, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] 0; if (ioctl(sockfd, SIOCGIFADDR, ifr) 0) { printf(ioctl error\n); close(sockfd); return ret; } memcpy(sin, ifr.ifr_addr, sizeof(sin)); int ip_len snprintf(_ip, 32, %s, inet_ntoa(sin.sin_addr)); close(sockfd); ret ip_len; return ret; } int main(int argc, char **argv) { char ip_str[32] {0}; get_local_ip(wlan1, ip_str); printf(ip %s\n, ip_str); return 0; }实现原理 通过ioctl系统调用和SIOCGIFADDR命令获取网络接口的IP地址信息。注意事项需要确保网络接口已配置IP地址多IP场景如IPv6需要特殊处理返回的是字符串形式需要确保缓冲区足够大扩展应用网络配置工具开发自动发现本地服务网络状态监控3. 代码优化与使用建议3.1 错误处理改进原始代码中的错误处理相对简单实际项目中建议使用更详细的错误日志包括errno信息资源释放需要更严谨如文件描述符泄漏问题考虑添加重试机制应对临时性错误3.2 性能优化方向频繁调用的函数可以考虑缓存结果文件操作可以批量处理减少IO次数关键路径考虑无锁或原子操作3.3 跨平台适配使用条件编译处理平台差异封装平台相关代码为独立模块提供统一的接口抽象4. 实际应用案例4.1 系统监控工具结合上述代码片段可以开发一个简单的系统监控工具定期收集并显示CPU温度内存使用情况网络状态系统负载4.2 调试信息增强在嵌入式系统调试中可以在崩溃日志中自动包含系统时间戳环境温度网络连接状态关键资源使用情况4.3 自动化测试框架这些基础功能可以作为测试框架的组成部分用于测试环境验证性能数据采集测试结果标记这些代码片段虽然简单但构成了很多系统工具的基础。在实际项目中我经常根据具体需求对它们进行扩展和组合解决各种实际问题。

更多文章