嵌入式Linux开发实用代码片段解析

张开发
2026/4/11 8:57:39 15 分钟阅读

分享文章

嵌入式Linux开发实用代码片段解析
1. 嵌入式Linux开发中的实用代码片段解析在嵌入式Linux开发过程中我们经常需要快速获取系统关键信息来辅助调试和问题定位。这些看似简单的功能在实际项目中却能显著提升开发效率。本文将分享几个经过实战检验的C语言代码片段它们涵盖了内存、CPU、文件系统、网络等核心系统信息的获取方法。这些代码片段的特点是直接调用Linux系统接口不依赖第三方库代码简洁但功能完整可直接集成到项目中经过实际项目验证稳定性有保障适用于大多数嵌入式Linux平台2. 系统资源监控相关代码2.1 获取内存信息内存监控是嵌入式系统调试的基础需求。通过定期记录内存使用情况可以快速发现内存泄漏或缓存膨胀等问题。#include stdio.h #include string.h #define PROC_MEMINFO /proc/meminfo int get_meminfo_kb(long *total_kb, long *avail_kb) { FILE *fp fopen(PROC_MEMINFO, r); if (NULL fp) { printf(fopen error\n); return -1; } char line[256] {0}; long total -1; long avail -1; while (NULL ! fgets(line, sizeof(line), fp)) { if (0 strncmp(line, MemTotal:, 9)) { sscanf(line, MemTotal: %ld kB, total); } else if (0 strncmp(line, MemAvailable:, 13)) { sscanf(line, MemAvailable: %ld kB, avail); } if (total 0 avail 0) { break; } } fclose(fp); if (total 0 || avail 0) { printf(parse error\n); return -1; } *total_kb total; *avail_kb avail; return 0; }注意不同Linux内核版本中/proc/meminfo的字段可能略有差异但MemTotal和MemAvailable在大多数发行版中都可用。实际应用建议定期如每分钟记录MemAvailable值观察变化趋势当可用内存低于某个阈值如总内存的10%时发出警告结合应用日志分析内存下降与特定操作的关系2.2 获取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; }提示在实际项目中建议将温度传感器路径做成可配置参数因为不同硬件平台可能使用不同的thermal_zone编号。常见问题处理如果无法打开温度文件检查/sys/class/thermal目录下是否有其他thermal_zone温度单位通常是毫摄氏度需要除以1000得到摄氏度采样频率不宜过高建议1-10秒一次避免影响系统性能2.3 获取CPU使用率CPU使用率是评估系统负载的重要指标正确的计算方法能准确反映实时负载情况。#include stdio.h #include unistd.h #define PROC_STAT /proc/stat static int read_cpu_stat(unsigned long long *idle, unsigned long long *total) { FILE *fp fopen(PROC_STAT, r); if (NULL fp) { printf(fopen error\n); return -1; } unsigned long long user0,nice0,system0,idle_v0,iowait0,irq0,softirq0,steal0; int ret fscanf(fp, cpu %llu %llu %llu %llu %llu %llu %llu %llu, user,nice,system,idle_v,iowait,irq,softirq,steal); fclose(fp); if (8 ! ret) { printf(fscanf error\n); return -1; } *idle idle_v iowait; *total user nice system idle_v iowait irq softirq steal; return 0; } int main(void) { unsigned long long idle10,total10,idle20,total20; read_cpu_stat(idle1, total1); usleep(200 * 1000); read_cpu_stat(idle2, total2); unsigned long long idle_delta idle2 - idle1; unsigned long long total_delta total2 - total1; double cpu_usage 0; if (total_delta 0) { cpu_usage (double)(total_delta - idle_delta) * 100.0 / (double)total_delta; } printf(cpu_usage %.2f %%\n, cpu_usage); return 0; }实现原理说明/proc/stat中的cpu行提供了自系统启动以来的累计CPU时间需要间隔一段时间如200ms采样两次数据通过计算两次采样间的差值得到这段时间内的CPU使用情况使用公式(总时间-空闲时间)/总时间*100% 计算使用率3. 文件系统相关操作3.1 获取文件大小文件大小信息在文件传输、存储管理等场景中经常需要用到。#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; }更严谨的实现可以考虑使用stat()函数#include sys/stat.h long get_file_size_stat(const char *filename) { struct stat st; if (stat(filename, st) 0) return st.st_size; return -1; }两种方法的比较fseek/ftell方法简单直观适用于普通文件stat()方法更可靠能处理特殊文件类型stat()还能获取更多文件属性如修改时间、权限等3.2 获取磁盘剩余空间磁盘空间监控可以预防因存储不足导致的各种问题。#include stdio.h #include sys/statvfs.h unsigned long long get_fs_free_bytes(const char *path) { struct statvfs st; if (0 ! statvfs(path, st)) { printf(statvfs error\n); return 0; } return (unsigned long long)st.f_bsize * (unsigned long long)st.f_bavail; }使用建议关键操作如文件写入、系统升级前检查磁盘空间监控重要分区如/、/var、/home等的剩余空间设置合理的预警阈值如剩余空间小于100MB时告警4. 网络信息获取4.1 获取MAC地址MAC地址常被用作设备唯一标识或生成设备ID的基础。#include stdio.h #include stdint.h #include net/if.h #include sys/socket.h #include sys/ioctl.h #include arpa/inet.h #include unistd.h #include string.h int get_netif_mac(const char *_ifr_name, char *_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; } strncpy(m_ifreq.ifr_name, _ifr_name, IFNAMSIZ); m_ifreq.ifr_name[IFNAMSIZ - 1] 0; 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; }注意事项网卡名称因系统而异eth0、wlan0、enp0s3等ifr_name长度有限制IFNAMSIZ拷贝时需确保字符串以\0结尾创建的socket仅用于ioctl调用不需要实际连接网络4.2 获取IP地址获取本机IP地址对于网络调试和设备管理非常有用。#include stdio.h #include net/if.h #include sys/socket.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; }替代方案 对于更复杂的需求如支持IPv6或多IP地址可以考虑使用getifaddrs()函数。但ioctl版本在嵌入式系统中更为常见依赖更少。5. 时间相关操作5.1 获取高精度时间戳精确的时间戳对于日志记录和性能分析至关重要。#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; }时间源选择建议gettimeofday()获取的是墙上时间可能受NTP或手动修改影响对于耗时测量推荐使用clock_gettime(CLOCK_MONOTONIC,...)确保项目中时间单位统一毫秒、微秒等便于日志分析6. 代码封装建议在实际项目中建议将这些功能封装成统一的工具库定义一致的错误码和返回格式添加日志记录功能便于调试为每个函数编写单元测试考虑线程安全性必要时添加互斥锁提供配置接口适应不同硬件平台示例封装结构libsysinfo/ ├── include/ │ ├── sysinfo.h │ └── sysinfo_error.h ├── src/ │ ├── memory.c │ ├── cpu.c │ ├── filesystem.c │ └── network.c └── tests/ ├── test_memory.c └── test_cpu.c在实际使用中我发现将这些基础功能封装成库后开发效率能提升30%以上。特别是在调试复杂问题时有了这些可靠的系统信息获取工具定位问题的速度明显加快。

更多文章