获取CPU温度
应用可以定时获取CPU温度,以便在程序异常崩溃时分析潜在原因,其中CPU温度可能是一个关键因素。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.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 = fopen(_cpu_temp_file, "r");
cpu_temperature_t cpu_temperature = {0};
int temp = 0;
if (fp == NULL) {
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 argc, char *argv[]) {
cpu_temperature_t cpu_temperature = get_cpu_temperature(CPU_TEMP_FILE0);
printf("cpu_temperature = %d.%d ℃\n", cpu_temperature.integer_part, cpu_temperature.decimal_part);
return 0;
}
获取文件大小
有时需要获取某个文件的大小,例如在发送文件内容之前需要知道文件的确切大小。
#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 (fp == NULL) {
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;
}
获取时间戳
系统时间戳在日志输出时非常有用,可以附带时间戳数据,方便后续分析。
#include <stdio.h>
#include <sys/time.h>
long long get_sys_time_ms(void) {
struct timeval sys_current_time;
gettimeofday(&sys_current_time, NULL);
return ((long long)sys_current_time.tv_sec * 1000) + (sys_current_time.tv_usec / 1000);
}
int main(int argc, char *argv[]) {
long long cur_sys_time = get_sys_time_ms();
printf("cur_sys_time = %lld ms\n", cur_sys_time);
return 0;
}
快速获取结构体成员大小及偏移量
获取结构体成员大小及偏移量的方式有多种,最简便的方式如下:
#include <stdio.h>
// 获取结构体成员大小
#define GET_MEMBER_SIZE(type, member) sizeof(((type*)0)->member)
// 获取结构体成员偏移量
#define GET_MEMBER_OFFSET(type, member) ((size_t)(&(((type*)0)->member)))
typedef struct _test_struct0 {
char x;
char y;
char z;
} test_struct0;
typedef struct _test_struct1 {
char a;
char c;
short b;
int d;
test_struct0 e;
} test_struct1;
int main(int argc, char *argv[]) {
printf("GET_MEMBER_SIZE(test_struct1, a) = %ld\n", GET_MEMBER_SIZE(test_struct1, a));
printf("GET_MEMBER_SIZE(test_struct1, c) = %ld\n", GET_MEMBER_SIZE(test_struct1, c));
printf("GET_MEMBER_SIZE(test_struct1, b) = %ld\n", GET_MEMBER_SIZE(test_struct1, b));
printf("GET_MEMBER_SIZE(test_struct1, d) = %ld\n", GET_MEMBER_SIZE(test_struct1, d));
printf("GET_MEMBER_SIZE(test_struct1, e) = %ld\n", GET_MEMBER_SIZE(test_struct1, e));
printf("test_struct1 size = %ld\n", sizeof(test_struct1));
printf("GET_MEMBER_OFFSET(a): %ld\n", GET_MEMBER_OFFSET(test_struct1, a));
printf("GET_MEMBER_OFFSET(c): %ld\n", GET_MEMBER_OFFSET(test_struct1, c));
printf("GET_MEMBER_OFFSET(b): %ld\n", GET_MEMBER_OFFSET(test_struct1, b));
printf("GET_MEMBER_OFFSET(d): %ld\n", GET_MEMBER_OFFSET(test_struct1, d));
printf("GET_MEMBER_OFFSET(e): %ld\n", GET_MEMBER_OFFSET(test_struct1, e));
return 0;
}
获取MAC地址
MAC地址有时会用作设备ID,是设备的唯一标识符之一。
#include <stdio.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
int get_netif_mac(const char *_ifr_name, uint8_t *_mac) {
struct ifreq m_ifreq;
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
printf("socket error\n");
return -1;
}
strcpy(m_ifreq.ifr_name, _ifr_name);
if (ioctl(sock, SIOCGIFHWADDR, &m_ifreq) < 0) {
printf("ioctl error\n");
close(sock);
return -1;
}
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]);
close(sock);
return 0;
}
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;
}
获取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 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
printf("socket error\n");
return -1;
}
struct ifreq ifr;
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 -1;
}
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
strncpy(_ip, inet_ntoa(sin->sin_addr), 32);
close(sockfd);
return 0;
}
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;
}
文件操作
文件操作在开发中非常常见,可以根据实际需求封装一层,方便使用。
#include <stdio.h>
static int file_opt_write(const char *filename, void *ptr, int size) {
FILE *fp = fopen(filename, "wb");
if (fp == NULL) {
printf("open %s file error!\n", filename);
return -1;
}
size_t num = fwrite(ptr, 1, size, fp);
if (num != size) {
fclose(fp);
printf("write %s file error!\n", filename);
return -1;
}
fclose(fp);
return num;
}
static int file_opt_read(const char *filename, void *ptr, int size) {
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
printf("open %s file error!\n", filename);
return -1;
}
size_t num = fread(ptr, 1, size, fp);
if (num != size) {
fclose(fp);
printf("read %s file error!\n", filename);
return -1;
}
fclose(fp);
return num;
}
typedef struct _test_struct {
char a;
char c;
short b;
int d;
} test_struct;
int main(int argc, char *argv[]) {
#define FILE_NAME "./test_file"
test_struct write_data = {1, 3, 2, 4};
printf("write_data.a = %d\n", write_data.a);
printf("write_data.b = %d\n
", write_data.b);
printf("write_data.c = %d\n", write_data.c);
printf("write_data.d = %d\n", write_data.d);
file_opt_write(FILE_NAME, &write_data, sizeof(test_struct));
test_struct read_data = {0};
file_opt_read(FILE_NAME, &read_data, sizeof(test_struct));
printf("read_data.a = %d\n", read_data.a);
printf("read_data.b = %d\n", read_data.b);
printf("read_data.c = %d\n", read_data.c);
printf("read_data.d = %d\n", read_data.d);
return 0;
}
进度条
在执行一些耗时操作时,进度条可以方便地显示当前的进度。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
typedef struct _progress {
int cur_size;
int sum_size;
} progress_t;
void progress_bar(progress_t *progress_data) {
int percentage = (int)(progress_data->cur_size * 100 / progress_data->sum_size);
char proc[102] = {0};
printf("percentage = %d %%\n", percentage);
if (percentage <= 100) {
for (int cnt = 0; cnt <= percentage; cnt++) {
printf("[%-100s] [%d%%]\r", proc, cnt);
fflush(stdout);
proc[cnt] = '#';
usleep(100000);
}
}
printf("\n");
}
int main(int argc, char *argv[]) {
progress_t progress_test = {65, 100};
progress_bar(&progress_test);
return 0;
}
日志输出
日志输出常常需要带一些格式化信息,以下是一个简单的日志输出方式。
#include <stdio.h>
#define LOG_D(fmt, args...) do { \
printf("<<File:%s Line:%d Function:%s>> ", __FILE__, __LINE__, __FUNCTION__); \
printf(fmt, ##args); \
} while(0)
int main(int argc, char *argv[]) {
char ch = 'a';
char str[10] = "ZhengN";
float float_val = 10.10;
int num = 88;
double double_val = 10.123456;
LOG_D("字符为 %c \n", ch);
LOG_D("字符串为 %s \n", str);
LOG_D("浮点数为 %f \n", float_val);
LOG_D("整数为 %d\n", num);
LOG_D("双精度值为 %lf \n", double_val);
LOG_D("八进制值为 %o \n", num);
LOG_D("十六进制值为 %x \n", num);
return 0;
}