活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

深入探索Linux系统开发中的void应用与实际案例分析 从基础概念到高级开发技巧全面解析Linux系统开发过程中void类型的使用场景与最佳实践

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-10 10:30:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1. void类型的基础概念

1.1 void类型的定义与本质

在C/C++编程语言中,void是一个特殊的数据类型,字面意思是”无类型”或”空类型”。它不能用于声明普通变量,因为编译器无法为其分配内存空间。例如,以下代码是非法的:
  1. void value; // 编译错误:不能声明void类型的变量
复制代码

void类型主要有三个用途:

• 作为函数返回类型,表示函数不返回值
• 作为函数参数列表,表示函数不接受任何参数
• 声明通用指针void*,可以指向任何类型的数据

1.2 void指针的特性

void*(指向void的指针)是一种特殊的指针类型,具有以下特性:
  1. int a = 10;
  2. char b = 'x';
  3. void *p;
  4. p = &a;  // 合法:void*可以指向任何类型
  5. p = &b;  // 合法:void*可以指向任何类型
  6. // *p;    // 非法:不能直接解引用void指针
  7. // p++;   // 非法:不能对void指针进行算术运算
复制代码

由于void*不指向具体类型,因此不能直接解引用或进行指针算术运算。在使用前必须将其转换为具体的类型指针:
  1. int a = 10;
  2. void *p = &a;
  3. int *int_p = (int*)p;  // 转换为int指针
  4. printf("%d\n", *int_p);  // 现在可以解引用
复制代码

1.3 Linux内核中void的特殊性

在Linux内核开发中,void和void*扮演着更加重要的角色。内核代码需要处理各种数据类型,同时保持高度抽象和通用性,void*正好满足了这一需求。

内核中的许多API使用void*作为参数或返回值,以实现通用性。例如,内存分配函数kmalloc()返回void*:
  1. void *kmalloc(size_t size, gfp_t flags);
复制代码

这使得kmalloc()可以分配任何类型的内存,由调用者决定如何使用这块内存。

2. void类型的使用场景

2.1 函数返回void的情况

当函数不需要返回值时,使用void作为返回类型。这在Linux系统编程中非常常见,特别是在执行操作但不返回结果的函数中:
  1. void exit(int status);
  2. void free(void *ptr);
  3. void *memset(void *s, int c, size_t n);
复制代码

示例:使用memset初始化内存
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main() {
  4.     char buffer[100];
  5.    
  6.     // 使用memset将buffer所有字节设置为0
  7.     memset(buffer, 0, sizeof(buffer));
  8.    
  9.     // 使用memset将buffer前10个字节设置为'A'
  10.     memset(buffer, 'A', 10);
  11.    
  12.     printf("Buffer content: %.10s\n", buffer);
  13.     return 0;
  14. }
复制代码

2.2 void指针的使用场景

void*在Linux系统开发中广泛用于实现通用接口。以下是几个典型场景:
  1. void *malloc(size_t size);
  2. void *calloc(size_t nmemb, size_t size);
  3. void *realloc(void *ptr, size_t size);
  4. void free(void *ptr);
复制代码

这些函数使用void*作为返回值或参数,使其能够处理任何类型的数据。

示例:动态内存分配
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main() {
  4.     // 分配存储10个整数的内存
  5.     int *int_array = (int*)malloc(10 * sizeof(int));
  6.     if (int_array == NULL) {
  7.         perror("malloc failed");
  8.         return 1;
  9.     }
  10.    
  11.     // 使用分配的内存
  12.     for (int i = 0; i < 10; i++) {
  13.         int_array[i] = i * 10;
  14.     }
  15.    
  16.     // 分配存储20个字符的内存
  17.     char *char_array = (char*)malloc(20 * sizeof(char));
  18.     if (char_array == NULL) {
  19.         perror("malloc failed");
  20.         free(int_array);
  21.         return 1;
  22.     }
  23.    
  24.     // 使用分配的内存
  25.     strcpy(char_array, "Hello, Linux!");
  26.    
  27.     printf("Integer array: %d, %d, %d\n", int_array[0], int_array[1], int_array[2]);
  28.     printf("Character array: %s\n", char_array);
  29.    
  30.     // 释放内存
  31.     free(int_array);
  32.     free(char_array);
  33.    
  34.     return 0;
  35. }
复制代码

在POSIX线程编程中,线程函数的参数和返回值都是void*类型:
  1. #include <pthread.h>
  2. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  3.                   void *(*start_routine)(void *), void *arg);
  4. int pthread_join(pthread_t thread, void **retval);
复制代码

示例:创建和使用线程
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. // 线程函数,接受void*参数,返回void*
  5. void* thread_function(void* arg) {
  6.     int* num = (int*)arg;
  7.     printf("Thread received: %d\n", *num);
  8.    
  9.     // 执行一些工作
  10.     for (int i = 0; i < 5; i++) {
  11.         printf("Thread working: %d\n", i);
  12.         sleep(1);
  13.     }
  14.    
  15.     // 分配返回值
  16.     int* result = (int*)malloc(sizeof(int));
  17.     *result = *num * 100;
  18.    
  19.     return (void*)result;
  20. }
  21. int main() {
  22.     pthread_t thread_id;
  23.     int input = 42;
  24.    
  25.     // 创建线程,传递参数
  26.     if (pthread_create(&thread_id, NULL, thread_function, &input) != 0) {
  27.         perror("pthread_create failed");
  28.         return 1;
  29.     }
  30.    
  31.     printf("Main thread waiting for worker thread to finish...\n");
  32.    
  33.     // 等待线程结束并获取返回值
  34.     void* thread_result;
  35.     if (pthread_join(thread_id, &thread_result) != 0) {
  36.         perror("pthread_join failed");
  37.         return 1;
  38.     }
  39.    
  40.     // 使用线程返回值
  41.     int* result = (int*)thread_result;
  42.     printf("Thread returned: %d\n", *result);
  43.    
  44.     // 释放线程返回值分配的内存
  45.     free(result);
  46.    
  47.     return 0;
  48. }
复制代码

2.3 函数参数为void的情况

在C语言中,函数参数列表中的void表示该函数不接受任何参数。这是显式声明无参函数的方式:
  1. int rand(void);  // 不接受参数的随机数函数
  2. void abort(void); // 不接受参数的终止函数
复制代码

注意:在C++中,空参数列表和(void)是等价的,但在C语言中,空参数列表意味着函数可以接受任意数量和类型的参数(这是C语言的旧特性),而(void)明确表示不接受任何参数。

示例:使用rand(void)函数
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. int main() {
  5.     // 初始化随机数种子
  6.     srand(time(NULL));
  7.    
  8.     // 生成并打印5个随机数
  9.     for (int i = 0; i < 5; i++) {
  10.         printf("Random number %d: %d\n", i, rand());
  11.     }
  12.    
  13.     return 0;
  14. }
复制代码

3. 实际案例分析

3.1 Linux内核中的void应用案例

在Linux内核模块编程中,void*经常用于实现通用接口。以下是一个简单的内核模块示例,展示了void和void*的使用:
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/slab.h>
  5. // 定义一个通用数据结构
  6. struct my_data {
  7.     void *data;      // 通用数据指针
  8.     size_t size;     // 数据大小
  9.     void (*process)(void *); // 处理数据的函数指针
  10. };
  11. // 处理整数数据的函数
  12. void process_int(void *data) {
  13.     int *num = (int*)data;
  14.     printk(KERN_INFO "Processing integer: %d\n", *num);
  15.     *num *= 2;  // 将整数乘以2
  16. }
  17. // 处理字符串数据的函数
  18. void process_string(void *data) {
  19.     char *str = (char*)data;
  20.     printk(KERN_INFO "Processing string: %s\n", str);
  21.     // 将字符串转换为大写
  22.     for (; *str; ++str) *str = toupper(*str);
  23. }
  24. // 初始化函数
  25. static int __init my_module_init(void) {
  26.     struct my_data int_data, str_data;
  27.     int num = 42;
  28.     char text[] = "hello kernel";
  29.    
  30.     printk(KERN_INFO "Module loaded\n");
  31.    
  32.     // 设置整数数据
  33.     int_data.data = &num;
  34.     int_data.size = sizeof(num);
  35.     int_data.process = process_int;
  36.    
  37.     // 设置字符串数据
  38.     str_data.data = text;
  39.     str_data.size = strlen(text) + 1;
  40.     str_data.process = process_string;
  41.    
  42.     // 处理数据
  43.     int_data.process(int_data.data);
  44.     str_data.process(str_data.data);
  45.    
  46.     printk(KERN_INFO "Processed integer: %d\n", num);
  47.     printk(KERN_INFO "Processed string: %s\n", (char*)str_data.data);
  48.    
  49.     return 0;
  50. }
  51. // 清理函数
  52. static void __exit my_module_exit(void) {
  53.     printk(KERN_INFO "Module unloaded\n");
  54. }
  55. module_init(my_module_init);
  56. module_exit(my_module_exit);
  57. MODULE_LICENSE("GPL");
  58. MODULE_AUTHOR("Your Name");
  59. MODULE_DESCRIPTION("A simple module demonstrating void usage");
复制代码

Linux内核广泛使用回调函数,而这些回调函数经常使用void*作为参数,以实现通用性。例如,在设备驱动模型中:
  1. // 内核中的工作队列结构
  2. struct work_struct {
  3.     atomic_long_t data;
  4.     struct list_head entry;
  5.     work_func_t func;  // 函数指针类型,实际是 void (*)(struct work_struct *)
  6. };
  7. // 定义工作队列处理函数
  8. typedef void (*work_func_t)(struct work_struct *work);
  9. // 示例:使用工作队列
  10. #include <linux/workqueue.h>
  11. struct my_work {
  12.     struct work_struct work;
  13.     void *data;  // 通用数据指针
  14. };
  15. // 工作队列处理函数
  16. static void my_work_handler(struct work_struct *work) {
  17.     struct my_work *my_work = container_of(work, struct my_work, work);
  18.     int *value = (int*)my_work->data;
  19.    
  20.     printk(KERN_INFO "Work queue handler processing data: %d\n", *value);
  21.    
  22.     // 释放工作队列结构
  23.     kfree(my_work);
  24. }
  25. // 创建并提交工作队列
  26. static void submit_work(int data) {
  27.     struct my_work *work;
  28.    
  29.     // 分配工作队列结构
  30.     work = kmalloc(sizeof(struct my_work), GFP_KERNEL);
  31.     if (!work) {
  32.         printk(KERN_ERR "Failed to allocate work\n");
  33.         return;
  34.     }
  35.    
  36.     // 初始化工作队列
  37.     INIT_WORK(&work->work, my_work_handler);
  38.    
  39.     // 设置数据
  40.     work->data = kmalloc(sizeof(int), GFP_KERNEL);
  41.     if (!work->data) {
  42.         kfree(work);
  43.         printk(KERN_ERR "Failed to allocate work data\n");
  44.         return;
  45.     }
  46.    
  47.     *(int*)work->data = data;
  48.    
  49.     // 提交工作队列到默认工作队列
  50.     schedule_work(&work->work);
  51. }
复制代码

3.2 系统编程中的void应用案例

在Linux系统编程中,信号处理函数使用void作为返回类型,并接受int参数表示信号编号:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <unistd.h>
  5. // 信号处理函数
  6. void signal_handler(int signum) {
  7.     printf("Caught signal %d\n", signum);
  8.    
  9.     if (signum == SIGINT) {
  10.         printf("Exiting...\n");
  11.         exit(0);
  12.     }
  13. }
  14. int main() {
  15.     // 注册信号处理函数
  16.     signal(SIGINT, signal_handler);  // Ctrl+C
  17.     signal(SIGTERM, signal_handler); // kill命令
  18.    
  19.     printf("Signal handler registered. PID: %d\n", getpid());
  20.     printf("Try sending SIGINT (Ctrl+C) or SIGTERM (kill %d)\n", getpid());
  21.    
  22.     // 无限循环等待信号
  23.     while(1) {
  24.         sleep(1);
  25.     }
  26.    
  27.     return 0;
  28. }
复制代码

在进程间通信中,共享内存经常使用void*来处理通用数据:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/ipc.h>
  4. #include <sys/shm.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <sys/wait.h>
  8. #define SHM_SIZE 1024
  9. int main() {
  10.     int shmid;
  11.     key_t key = IPC_PRIVATE;
  12.     void *shm_ptr;
  13.     pid_t pid;
  14.    
  15.     // 创建共享内存
  16.     shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
  17.     if (shmid == -1) {
  18.         perror("shmget failed");
  19.         exit(1);
  20.     }
  21.    
  22.     // 将共享内存附加到进程地址空间
  23.     shm_ptr = shmat(shmid, NULL, 0);
  24.     if (shm_ptr == (void*)-1) {
  25.         perror("shmat failed");
  26.         exit(1);
  27.     }
  28.    
  29.     // 创建子进程
  30.     pid = fork();
  31.    
  32.     if (pid < 0) {
  33.         perror("fork failed");
  34.         exit(1);
  35.     } else if (pid == 0) {
  36.         // 子进程
  37.         printf("Child process writing to shared memory...\n");
  38.         
  39.         // 将共享内存视为字符数组
  40.         char *str = (char*)shm_ptr;
  41.         strcpy(str, "Hello from child process!");
  42.         
  43.         // 也可以将共享内存视为整数数组
  44.         int *nums = (int*)shm_ptr;
  45.         nums[10] = 42;
  46.         
  47.         printf("Child process finished writing\n");
  48.         exit(0);
  49.     } else {
  50.         // 父进程
  51.         // 等待子进程完成
  52.         wait(NULL);
  53.         
  54.         printf("Parent process reading from shared memory...\n");
  55.         
  56.         // 将共享内存视为字符数组
  57.         char *str = (char*)shm_ptr;
  58.         printf("Message from child: %s\n", str);
  59.         
  60.         // 将共享内存视为整数数组
  61.         int *nums = (int*)shm_ptr;
  62.         printf("Number from child: %d\n", nums[10]);
  63.         
  64.         // 分离共享内存
  65.         shmdt(shm_ptr);
  66.         
  67.         // 删除共享内存
  68.         shmctl(shmid, IPC_RMID, NULL);
  69.     }
  70.    
  71.     return 0;
  72. }
复制代码

3.3 驱动开发中的void应用案例

在Linux设备驱动开发中,void*经常用于实现通用设备接口和私有数据传递。以下是一个简单的字符设备驱动示例:
  1. #include <linux/module.h>
  2. #include <linux/fs.h>
  3. #include <linux/cdev.h>
  4. #include <linux/device.h>
  5. #include <linux/uaccess.h>
  6. #define DEVICE_NAME "void_example"
  7. #define CLASS_NAME  "void_class"
  8. #define MAX_DEVICES 1
  9. // 设备结构体
  10. struct void_device {
  11.     struct cdev cdev;
  12.     void *private_data;  // 通用私有数据指针
  13.     size_t data_size;    // 数据大小
  14. };
  15. static dev_t dev_num;
  16. static struct class *void_class;
  17. static struct void_device void_devices[MAX_DEVICES];
  18. // 设备打开函数
  19. static int void_device_open(struct inode *inode, struct file *file) {
  20.     struct void_device *dev;
  21.    
  22.     // 获取设备结构体
  23.     dev = container_of(inode->i_cdev, struct void_device, cdev);
  24.    
  25.     // 将设备结构体保存到文件的私有数据中
  26.     file->private_data = dev;
  27.    
  28.     printk(KERN_INFO "Device opened\n");
  29.     return 0;
  30. }
  31. // 设备释放函数
  32. static int void_device_release(struct inode *inode, struct file *file) {
  33.     printk(KERN_INFO "Device released\n");
  34.     return 0;
  35. }
  36. // 设备读取函数
  37. static ssize_t void_device_read(struct file *file, char __user *buf, size_t count, loff_t *offset) {
  38.     struct void_device *dev = file->private_data;
  39.     int ret;
  40.    
  41.     // 检查偏移量是否超出范围
  42.     if (*offset >= dev->data_size)
  43.         return 0;
  44.    
  45.     // 确定要读取的字节数
  46.     if (*offset + count > dev->data_size)
  47.         count = dev->data_size - *offset;
  48.    
  49.     // 将数据从内核空间复制到用户空间
  50.     ret = copy_to_user(buf, dev->private_data + *offset, count);
  51.     if (ret != 0) {
  52.         printk(KERN_ERR "Failed to copy data to user\n");
  53.         return -EFAULT;
  54.     }
  55.    
  56.     // 更新偏移量
  57.     *offset += count;
  58.    
  59.     return count;
  60. }
  61. // 设备写入函数
  62. static ssize_t void_device_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) {
  63.     struct void_device *dev = file->private_data;
  64.     int ret;
  65.    
  66.     // 检查偏移量是否超出范围
  67.     if (*offset >= dev->data_size)
  68.         return 0;
  69.    
  70.     // 确定要写入的字节数
  71.     if (*offset + count > dev->data_size)
  72.         count = dev->data_size - *offset;
  73.    
  74.     // 将数据从用户空间复制到内核空间
  75.     ret = copy_from_user(dev->private_data + *offset, buf, count);
  76.     if (ret != 0) {
  77.         printk(KERN_ERR "Failed to copy data from user\n");
  78.         return -EFAULT;
  79.     }
  80.    
  81.     // 更新偏移量
  82.     *offset += count;
  83.    
  84.     return count;
  85. }
  86. // 文件操作结构体
  87. static const struct file_operations void_fops = {
  88.     .owner = THIS_MODULE,
  89.     .open = void_device_open,
  90.     .release = void_device_release,
  91.     .read = void_device_read,
  92.     .write = void_device_write,
  93. };
  94. // 模块初始化函数
  95. static int __init void_driver_init(void) {
  96.     int ret, i;
  97.    
  98.     // 分配设备号
  99.     ret = alloc_chrdev_region(&dev_num, 0, MAX_DEVICES, DEVICE_NAME);
  100.     if (ret < 0) {
  101.         printk(KERN_ERR "Failed to allocate device numbers\n");
  102.         return ret;
  103.     }
  104.    
  105.     // 创建设备类
  106.     void_class = class_create(THIS_MODULE, CLASS_NAME);
  107.     if (IS_ERR(void_class)) {
  108.         printk(KERN_ERR "Failed to create device class\n");
  109.         unregister_chrdev_region(dev_num, MAX_DEVICES);
  110.         return PTR_ERR(void_class);
  111.     }
  112.    
  113.     // 初始化设备
  114.     for (i = 0; i < MAX_DEVICES; i++) {
  115.         // 分配私有数据缓冲区
  116.         void_devices[i].private_data = kmalloc(1024, GFP_KERNEL);
  117.         if (!void_devices[i].private_data) {
  118.             printk(KERN_ERR "Failed to allocate private data\n");
  119.             // 清理已分配的资源
  120.             for (int j = 0; j < i; j++) {
  121.                 kfree(void_devices[j].private_data);
  122.                 device_destroy(void_class, MKDEV(MAJOR(dev_num), MINOR(dev_num) + j));
  123.                 cdev_del(&void_devices[j].cdev);
  124.             }
  125.             class_destroy(void_class);
  126.             unregister_chrdev_region(dev_num, MAX_DEVICES);
  127.             return -ENOMEM;
  128.         }
  129.         
  130.         void_devices[i].data_size = 1024;
  131.         
  132.         // 初始化字符设备
  133.         cdev_init(&void_devices[i].cdev, &void_fops);
  134.         void_devices[i].cdev.owner = THIS_MODULE;
  135.         
  136.         // 添加字符设备
  137.         ret = cdev_add(&void_devices[i].cdev, MKDEV(MAJOR(dev_num), MINOR(dev_num) + i), 1);
  138.         if (ret < 0) {
  139.             printk(KERN_ERR "Failed to add character device\n");
  140.             // 清理已分配的资源
  141.             kfree(void_devices[i].private_data);
  142.             for (int j = 0; j < i; j++) {
  143.                 kfree(void_devices[j].private_data);
  144.                 device_destroy(void_class, MKDEV(MAJOR(dev_num), MINOR(dev_num) + j));
  145.                 cdev_del(&void_devices[j].cdev);
  146.             }
  147.             class_destroy(void_class);
  148.             unregister_chrdev_region(dev_num, MAX_DEVICES);
  149.             return ret;
  150.         }
  151.         
  152.         // 创建设备文件
  153.         device_create(void_class, NULL, MKDEV(MAJOR(dev_num), MINOR(dev_num) + i), NULL, "%s%d", DEVICE_NAME, i);
  154.     }
  155.    
  156.     printk(KERN_INFO "Void driver loaded with major number %d\n", MAJOR(dev_num));
  157.     return 0;
  158. }
  159. // 模块清理函数
  160. static void __exit void_driver_exit(void) {
  161.     int i;
  162.    
  163.     // 清理设备
  164.     for (i = 0; i < MAX_DEVICES; i++) {
  165.         device_destroy(void_class, MKDEV(MAJOR(dev_num), MINOR(dev_num) + i));
  166.         cdev_del(&void_devices[i].cdev);
  167.         kfree(void_devices[i].private_data);
  168.     }
  169.    
  170.     // 清理类和设备号
  171.     class_destroy(void_class);
  172.     unregister_chrdev_region(dev_num, MAX_DEVICES);
  173.    
  174.     printk(KERN_INFO "Void driver unloaded\n");
  175. }
  176. module_init(void_driver_init);
  177. module_exit(void_driver_exit);
  178. MODULE_LICENSE("GPL");
  179. MODULE_AUTHOR("Your Name");
  180. MODULE_DESCRIPTION("A driver demonstrating void usage");
复制代码

3.4 多线程编程中的void应用

在多线程编程中,void*经常用于线程函数的参数和返回值,以实现通用性:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <unistd.h>
  5. // 任务结构体
  6. typedef struct {
  7.     int id;
  8.     void *data;
  9.     void (*process)(void *);
  10. } Task;
  11. // 处理整数数据的任务
  12. void process_int_task(void *data) {
  13.     int *num = (int*)data;
  14.     printf("Task processing integer: %d\n", *num);
  15.     sleep(1);  // 模拟处理时间
  16.     *num *= 2;
  17.     printf("Task result: %d\n", *num);
  18. }
  19. // 处理字符串数据的任务
  20. void process_string_task(void *data) {
  21.     char *str = (char*)data;
  22.     printf("Task processing string: %s\n", str);
  23.     sleep(1);  // 模拟处理时间
  24.    
  25.     // 将字符串转换为大写
  26.     for (; *str; ++str) *str = toupper(*str);
  27.     printf("Task result: %s\n", str - strlen(str));
  28. }
  29. // 线程函数
  30. void* worker_thread(void *arg) {
  31.     Task *task = (Task*)arg;
  32.    
  33.     printf("Worker thread %d started\n", task->id);
  34.    
  35.     // 执行任务处理函数
  36.     task->process(task->data);
  37.    
  38.     printf("Worker thread %d finished\n", task->id);
  39.    
  40.     // 返回任务ID作为结果
  41.     return (void*)(long)task->id;
  42. }
  43. int main() {
  44.     pthread_t threads[4];
  45.     Task tasks[4];
  46.     int int_data[2] = {10, 20};
  47.     char str_data[2][20] = {"hello", "world"};
  48.     int i;
  49.    
  50.     // 创建并初始化任务
  51.     for (i = 0; i < 4; i++) {
  52.         tasks[i].id = i;
  53.         
  54.         if (i % 2 == 0) {
  55.             // 整数处理任务
  56.             tasks[i].data = &int_data[i/2];
  57.             tasks[i].process = process_int_task;
  58.         } else {
  59.             // 字符串处理任务
  60.             tasks[i].data = str_data[i/2];
  61.             tasks[i].process = process_string_task;
  62.         }
  63.         
  64.         // 创建工作线程
  65.         if (pthread_create(&threads[i], NULL, worker_thread, &tasks[i]) != 0) {
  66.             perror("Failed to create thread");
  67.             exit(1);
  68.         }
  69.     }
  70.    
  71.     // 等待所有线程完成
  72.     for (i = 0; i < 4; i++) {
  73.         void *result;
  74.         if (pthread_join(threads[i], &result) != 0) {
  75.             perror("Failed to join thread");
  76.             exit(1);
  77.         }
  78.         
  79.         printf("Thread %d completed with result: %ld\n", i, (long)result);
  80.     }
  81.    
  82.     // 打印最终结果
  83.     printf("Final integer data: %d, %d\n", int_data[0], int_data[1]);
  84.     printf("Final string data: %s, %s\n", str_data[0], str_data[1]);
  85.    
  86.     return 0;
  87. }
复制代码

4. 高级开发技巧

4.1 void指针的类型转换技巧

在Linux系统开发中,正确使用void*类型转换是关键。以下是一些高级技巧:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义类型转换宏
  4. #define VOID_TO_INT(ptr)    (*((int*)(ptr)))
  5. #define VOID_TO_CHAR(ptr)   (*((char*)(ptr)))
  6. #define VOID_TO_FLOAT(ptr)  (*((float*)(ptr)))
  7. // 通用处理函数
  8. void process_data(void *data, int type) {
  9.     switch (type) {
  10.         case 1:  // 整数
  11.             printf("Processing integer: %d\n", VOID_TO_INT(data));
  12.             VOID_TO_INT(data) *= 2;
  13.             printf("Result: %d\n", VOID_TO_INT(data));
  14.             break;
  15.         case 2:  // 字符
  16.             printf("Processing character: %c\n", VOID_TO_CHAR(data));
  17.             VOID_TO_CHAR(data) = toupper(VOID_TO_CHAR(data));
  18.             printf("Result: %c\n", VOID_TO_CHAR(data));
  19.             break;
  20.         case 3:  // 浮点数
  21.             printf("Processing float: %f\n", VOID_TO_FLOAT(data));
  22.             VOID_TO_FLOAT(data) *= 1.5;
  23.             printf("Result: %f\n", VOID_TO_FLOAT(data));
  24.             break;
  25.         default:
  26.             printf("Unknown data type\n");
  27.     }
  28. }
  29. int main() {
  30.     int i = 42;
  31.     char c = 'a';
  32.     float f = 3.14;
  33.    
  34.     process_data(&i, 1);
  35.     process_data(&c, 2);
  36.     process_data(&f, 3);
  37.    
  38.     return 0;
  39. }
复制代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义数据类型枚举
  4. typedef enum {
  5.     DATA_INT,
  6.     DATA_CHAR,
  7.     DATA_FLOAT,
  8.     DATA_POINTER
  9. } DataType;
  10. // 定义通用数据结构
  11. typedef struct {
  12.     DataType type;
  13.     union {
  14.         int int_val;
  15.         char char_val;
  16.         float float_val;
  17.         void *ptr_val;
  18.     } data;
  19. } GenericData;
  20. // 通用处理函数
  21. void process_generic_data(GenericData *data) {
  22.     switch (data->type) {
  23.         case DATA_INT:
  24.             printf("Processing integer: %d\n", data->data.int_val);
  25.             data->data.int_val *= 2;
  26.             printf("Result: %d\n", data->data.int_val);
  27.             break;
  28.         case DATA_CHAR:
  29.             printf("Processing character: %c\n", data->data.char_val);
  30.             data->data.char_val = toupper(data->data.char_val);
  31.             printf("Result: %c\n", data->data.char_val);
  32.             break;
  33.         case DATA_FLOAT:
  34.             printf("Processing float: %f\n", data->data.float_val);
  35.             data->data.float_val *= 1.5;
  36.             printf("Result: %f\n", data->data.float_val);
  37.             break;
  38.         case DATA_POINTER:
  39.             printf("Processing pointer: %p\n", data->data.ptr_val);
  40.             // 假设指针指向整数
  41.             if (data->data.ptr_val) {
  42.                 int *int_ptr = (int*)data->data.ptr_val;
  43.                 printf("Pointed value: %d\n", *int_ptr);
  44.                 (*int_ptr)++;
  45.                 printf("New pointed value: %d\n", *int_ptr);
  46.             }
  47.             break;
  48.         default:
  49.             printf("Unknown data type\n");
  50.     }
  51. }
  52. int main() {
  53.     int value = 42;
  54.     GenericData data[4];
  55.    
  56.     // 初始化数据
  57.     data[0].type = DATA_INT;
  58.     data[0].data.int_val = 10;
  59.    
  60.     data[1].type = DATA_CHAR;
  61.     data[1].data.char_val = 'b';
  62.    
  63.     data[2].type = DATA_FLOAT;
  64.     data[2].data.float_val = 2.71;
  65.    
  66.     data[3].type = DATA_POINTER;
  67.     data[3].data.ptr_val = &value;
  68.    
  69.     // 处理数据
  70.     for (int i = 0; i < 4; i++) {
  71.         process_generic_data(&data[i]);
  72.     }
  73.    
  74.     printf("Original value after pointer processing: %d\n", value);
  75.    
  76.     return 0;
  77. }
复制代码

4.2 void与函数指针的高级应用

函数指针与void*结合使用可以实现高度灵活的回调机制和插件系统:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. // 定义函数指针类型
  5. typedef void (*CallbackFunc)(void *, void *);
  6. // 定义任务结构体
  7. typedef struct {
  8.     void *input;
  9.     void *output;
  10.     CallbackFunc callback;
  11. } Task;
  12. // 整数处理回调函数
  13. void int_callback(void *input, void *output) {
  14.     int *in = (int*)input;
  15.     int *out = (int*)output;
  16.    
  17.     printf("Processing integer: %d\n", *in);
  18.     *out = *in * 2;
  19.     printf("Result: %d\n", *out);
  20. }
  21. // 字符串处理回调函数
  22. void string_callback(void *input, void *output) {
  23.     char *in = (char*)input;
  24.     char *out = (char*)output;
  25.    
  26.     printf("Processing string: %s\n", in);
  27.    
  28.     // 将字符串转换为大写并复制到输出
  29.     int i;
  30.     for (i = 0; in[i]; i++) {
  31.         out[i] = toupper(in[i]);
  32.     }
  33.     out[i] = '\0';
  34.    
  35.     printf("Result: %s\n", out);
  36. }
  37. // 任务执行器
  38. void execute_task(Task *task) {
  39.     if (task && task->callback) {
  40.         task->callback(task->input, task->output);
  41.     }
  42. }
  43. // 任务队列
  44. typedef struct {
  45.     Task *tasks;
  46.     int count;
  47.     int capacity;
  48. } TaskQueue;
  49. // 初始化任务队列
  50. TaskQueue* create_task_queue(int capacity) {
  51.     TaskQueue *queue = (TaskQueue*)malloc(sizeof(TaskQueue));
  52.     if (!queue) return NULL;
  53.    
  54.     queue->tasks = (Task*)malloc(capacity * sizeof(Task));
  55.     if (!queue->tasks) {
  56.         free(queue);
  57.         return NULL;
  58.     }
  59.    
  60.     queue->count = 0;
  61.     queue->capacity = capacity;
  62.    
  63.     return queue;
  64. }
  65. // 添加任务到队列
  66. int add_task(TaskQueue *queue, void *input, void *output, CallbackFunc callback) {
  67.     if (queue->count >= queue->capacity) {
  68.         return -1;  // 队列已满
  69.     }
  70.    
  71.     Task *task = &queue->tasks[queue->count++];
  72.     task->input = input;
  73.     task->output = output;
  74.     task->callback = callback;
  75.    
  76.     return 0;
  77. }
  78. // 执行队列中的所有任务
  79. void execute_all_tasks(TaskQueue *queue) {
  80.     for (int i = 0; i < queue->count; i++) {
  81.         execute_task(&queue->tasks[i]);
  82.     }
  83. }
  84. // 释放任务队列
  85. void free_task_queue(TaskQueue *queue) {
  86.     if (queue) {
  87.         free(queue->tasks);
  88.         free(queue);
  89.     }
  90. }
  91. int main() {
  92.     // 创建任务队列
  93.     TaskQueue *queue = create_task_queue(10);
  94.     if (!queue) {
  95.         printf("Failed to create task queue\n");
  96.         return 1;
  97.     }
  98.    
  99.     // 准备数据
  100.     int int_input = 21;
  101.     int int_output;
  102.    
  103.     char str_input[] = "hello world";
  104.     char str_output[50];
  105.    
  106.     // 添加任务
  107.     add_task(queue, &int_input, &int_output, int_callback);
  108.     add_task(queue, str_input, str_output, string_callback);
  109.    
  110.     // 执行所有任务
  111.     execute_all_tasks(queue);
  112.    
  113.     // 打印结果
  114.     printf("Final integer result: %d\n", int_output);
  115.     printf("Final string result: %s\n", str_output);
  116.    
  117.     // 释放资源
  118.     free_task_queue(queue);
  119.    
  120.     return 0;
  121. }
复制代码

4.3 void在内存管理中的应用

在Linux系统开发中,void*在内存管理中扮演着重要角色。以下是一个自定义内存池的实现示例:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <pthread.h>
  5. // 内存块结构体
  6. typedef struct MemoryBlock {
  7.     size_t size;
  8.     int free;
  9.     struct MemoryBlock *next;
  10.     void *memory;
  11. } MemoryBlock;
  12. // 内存池结构体
  13. typedef struct {
  14.     void *pool;          // 内存池起始地址
  15.     size_t pool_size;    // 内存池总大小
  16.     MemoryBlock *blocks; // 内存块链表
  17.     pthread_mutex_t mutex; // 互斥锁,用于线程安全
  18. } MemoryPool;
  19. // 创建内存池
  20. MemoryPool* create_memory_pool(size_t pool_size) {
  21.     MemoryPool *mp = (MemoryPool*)malloc(sizeof(MemoryPool));
  22.     if (!mp) return NULL;
  23.    
  24.     mp->pool = malloc(pool_size);
  25.     if (!mp->pool) {
  26.         free(mp);
  27.         return NULL;
  28.     }
  29.    
  30.     mp->pool_size = pool_size;
  31.     mp->blocks = (MemoryBlock*)malloc(sizeof(MemoryBlock));
  32.     if (!mp->blocks) {
  33.         free(mp->pool);
  34.         free(mp);
  35.         return NULL;
  36.     }
  37.    
  38.     // 初始化第一个内存块
  39.     mp->blocks->size = pool_size - sizeof(MemoryBlock);
  40.     mp->blocks->free = 1;
  41.     mp->blocks->next = NULL;
  42.     mp->blocks->memory = (char*)mp->pool + sizeof(MemoryBlock);
  43.    
  44.     // 初始化互斥锁
  45.     pthread_mutex_init(&mp->mutex, NULL);
  46.    
  47.     return mp;
  48. }
  49. // 从内存池分配内存
  50. void* pool_alloc(MemoryPool *mp, size_t size) {
  51.     if (!mp || size == 0) return NULL;
  52.    
  53.     // 对齐大小
  54.     size = (size + 7) & ~7;  // 8字节对齐
  55.    
  56.     pthread_mutex_lock(&mp->mutex);
  57.    
  58.     MemoryBlock *block = mp->blocks;
  59.     MemoryBlock *prev = NULL;
  60.    
  61.     while (block) {
  62.         if (block->free && block->size >= size) {
  63.             // 找到合适的内存块
  64.             
  65.             // 如果块足够大,分割它
  66.             if (block->size > size + sizeof(MemoryBlock) + 8) {
  67.                 MemoryBlock *new_block = (MemoryBlock*)((char*)block->memory + size);
  68.                 new_block->size = block->size - size - sizeof(MemoryBlock);
  69.                 new_block->free = 1;
  70.                 new_block->next = block->next;
  71.                 new_block->memory = (char*)new_block + sizeof(MemoryBlock);
  72.                
  73.                 block->size = size;
  74.                 block->next = new_block;
  75.             }
  76.             
  77.             block->free = 0;
  78.             pthread_mutex_unlock(&mp->mutex);
  79.             return block->memory;
  80.         }
  81.         
  82.         prev = block;
  83.         block = block->next;
  84.     }
  85.    
  86.     pthread_mutex_unlock(&mp->mutex);
  87.     return NULL;  // 没有找到合适的内存块
  88. }
  89. // 释放内存回内存池
  90. void pool_free(MemoryPool *mp, void *ptr) {
  91.     if (!mp || !ptr) return;
  92.    
  93.     pthread_mutex_lock(&mp->mutex);
  94.    
  95.     MemoryBlock *block = mp->blocks;
  96.    
  97.     while (block) {
  98.         if (block->memory == ptr) {
  99.             block->free = 1;
  100.             
  101.             // 合并相邻的空闲块
  102.             MemoryBlock *current = mp->blocks;
  103.             while (current) {
  104.                 if (current->free && current->next && current->next->free) {
  105.                     current->size += current->next->size + sizeof(MemoryBlock);
  106.                     MemoryBlock *temp = current->next;
  107.                     current->next = current->next->next;
  108.                     // 注意:这里我们不释放temp,因为它在池内
  109.                 }
  110.                 current = current->next;
  111.             }
  112.             
  113.             pthread_mutex_unlock(&mp->mutex);
  114.             return;
  115.         }
  116.         
  117.         block = block->next;
  118.     }
  119.    
  120.     pthread_mutex_unlock(&mp->mutex);
  121.     printf("Error: Pointer not found in memory pool\n");
  122. }
  123. // 销毁内存池
  124. void destroy_memory_pool(MemoryPool *mp) {
  125.     if (mp) {
  126.         pthread_mutex_destroy(&mp->mutex);
  127.         free(mp->blocks);
  128.         free(mp->pool);
  129.         free(mp);
  130.     }
  131. }
  132. // 打印内存池状态
  133. void print_pool_status(MemoryPool *mp) {
  134.     if (!mp) return;
  135.    
  136.     pthread_mutex_lock(&mp->mutex);
  137.    
  138.     printf("Memory Pool Status:\n");
  139.     printf("Total size: %zu bytes\n", mp->pool_size);
  140.    
  141.     MemoryBlock *block = mp->blocks;
  142.     int block_count = 0;
  143.     size_t free_size = 0;
  144.     size_t used_size = 0;
  145.    
  146.     while (block) {
  147.         printf("Block %d: size=%zu, free=%d\n", block_count++, block->size, block->free);
  148.         if (block->free) {
  149.             free_size += block->size;
  150.         } else {
  151.             used_size += block->size;
  152.         }
  153.         block = block->next;
  154.     }
  155.    
  156.     printf("Total blocks: %d\n", block_count);
  157.     printf("Used memory: %zu bytes\n", used_size);
  158.     printf("Free memory: %zu bytes\n", free_size);
  159.     printf("Overhead: %zu bytes\n", mp->pool_size - used_size - free_size);
  160.    
  161.     pthread_mutex_unlock(&mp->mutex);
  162. }
  163. int main() {
  164.     // 创建内存池
  165.     size_t pool_size = 1024;  // 1KB内存池
  166.     MemoryPool *mp = create_memory_pool(pool_size);
  167.     if (!mp) {
  168.         printf("Failed to create memory pool\n");
  169.         return 1;
  170.     }
  171.    
  172.     printf("Memory pool created with size %zu bytes\n", pool_size);
  173.     print_pool_status(mp);
  174.    
  175.     // 分配一些内存
  176.     void *ptr1 = pool_alloc(mp, 100);
  177.     void *ptr2 = pool_alloc(mp, 200);
  178.     void *ptr3 = pool_alloc(mp, 50);
  179.    
  180.     printf("\nAfter allocation:\n");
  181.     print_pool_status(mp);
  182.    
  183.     // 使用分配的内存
  184.     if (ptr1) {
  185.         strcpy((char*)ptr1, "This is a test string for ptr1");
  186.         printf("ptr1: %s\n", (char*)ptr1);
  187.     }
  188.    
  189.     if (ptr2) {
  190.         strcpy((char*)ptr2, "This is a longer test string for ptr2");
  191.         printf("ptr2: %s\n", (char*)ptr2);
  192.     }
  193.    
  194.     if (ptr3) {
  195.         strcpy((char*)ptr3, "Short string");
  196.         printf("ptr3: %s\n", (char*)ptr3);
  197.     }
  198.    
  199.     // 释放一些内存
  200.     pool_free(mp, ptr2);
  201.     printf("\nAfter freeing ptr2:\n");
  202.     print_pool_status(mp);
  203.    
  204.     // 再次分配内存
  205.     void *ptr4 = pool_alloc(mp, 180);
  206.     printf("\nAfter allocating ptr4 (180 bytes):\n");
  207.     print_pool_status(mp);
  208.    
  209.     if (ptr4) {
  210.         strcpy((char*)ptr4, "This is a new string in the freed space");
  211.         printf("ptr4: %s\n", (char*)ptr4);
  212.     }
  213.    
  214.     // 销毁内存池
  215.     destroy_memory_pool(mp);
  216.    
  217.     return 0;
  218. }
复制代码

4.4 void在数据结构抽象中的应用

void*在实现通用数据结构时非常有用,例如通用链表、哈希表等。以下是一个通用链表的实现:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. // 链表节点结构体
  5. typedef struct ListNode {
  6.     void *data;              // 通用数据指针
  7.     struct ListNode *next;    // 下一个节点
  8. } ListNode;
  9. // 链表结构体
  10. typedef struct {
  11.     ListNode *head;          // 链表头
  12.     ListNode *tail;          // 链表尾
  13.     int count;               // 节点计数
  14.     void (*free_func)(void*); // 数据释放函数
  15. } LinkedList;
  16. // 创建链表
  17. LinkedList* create_linked_list(void (*free_func)(void*)) {
  18.     LinkedList *list = (LinkedList*)malloc(sizeof(LinkedList));
  19.     if (!list) return NULL;
  20.    
  21.     list->head = NULL;
  22.     list->tail = NULL;
  23.     list->count = 0;
  24.     list->free_func = free_func;
  25.    
  26.     return list;
  27. }
  28. // 释放链表节点数据
  29. void default_free_func(void *data) {
  30.     free(data);
  31. }
  32. // 在链表尾部添加节点
  33. int append_to_list(LinkedList *list, void *data) {
  34.     if (!list) return -1;
  35.    
  36.     ListNode *node = (ListNode*)malloc(sizeof(ListNode));
  37.     if (!node) return -1;
  38.    
  39.     node->data = data;
  40.     node->next = NULL;
  41.    
  42.     if (list->tail) {
  43.         list->tail->next = node;
  44.         list->tail = node;
  45.     } else {
  46.         list->head = node;
  47.         list->tail = node;
  48.     }
  49.    
  50.     list->count++;
  51.     return 0;
  52. }
  53. // 在链表头部添加节点
  54. int prepend_to_list(LinkedList *list, void *data) {
  55.     if (!list) return -1;
  56.    
  57.     ListNode *node = (ListNode*)malloc(sizeof(ListNode));
  58.     if (!node) return -1;
  59.    
  60.     node->data = data;
  61.     node->next = list->head;
  62.    
  63.     list->head = node;
  64.    
  65.     if (!list->tail) {
  66.         list->tail = node;
  67.     }
  68.    
  69.     list->count++;
  70.     return 0;
  71. }
  72. // 从链表中删除节点
  73. int remove_from_list(LinkedList *list, void *data, int (*compare_func)(const void*, const void*)) {
  74.     if (!list || !list->head || !data || !compare_func) return -1;
  75.    
  76.     ListNode *prev = NULL;
  77.     ListNode *current = list->head;
  78.    
  79.     while (current) {
  80.         if (compare_func(current->data, data) == 0) {
  81.             // 找到匹配的节点
  82.             if (prev) {
  83.                 prev->next = current->next;
  84.             } else {
  85.                 list->head = current->next;
  86.             }
  87.             
  88.             if (current == list->tail) {
  89.                 list->tail = prev;
  90.             }
  91.             
  92.             if (list->free_func) {
  93.                 list->free_func(current->data);
  94.             }
  95.             
  96.             free(current);
  97.             list->count--;
  98.             return 0;
  99.         }
  100.         
  101.         prev = current;
  102.         current = current->next;
  103.     }
  104.    
  105.     return -1;  // 未找到匹配的节点
  106. }
  107. // 查找链表中的节点
  108. void* find_in_list(LinkedList *list, void *data, int (*compare_func)(const void*, const void*)) {
  109.     if (!list || !list->head || !data || !compare_func) return NULL;
  110.    
  111.     ListNode *current = list->head;
  112.    
  113.     while (current) {
  114.         if (compare_func(current->data, data) == 0) {
  115.             return current->data;
  116.         }
  117.         current = current->next;
  118.     }
  119.    
  120.     return NULL;  // 未找到匹配的节点
  121. }
  122. // 遍历链表
  123. void traverse_list(LinkedList *list, void (*visit_func)(void*)) {
  124.     if (!list || !visit_func) return;
  125.    
  126.     ListNode *current = list->head;
  127.    
  128.     while (current) {
  129.         visit_func(current->data);
  130.         current = current->next;
  131.     }
  132. }
  133. // 清空链表
  134. void clear_linked_list(LinkedList *list) {
  135.     if (!list) return;
  136.    
  137.     ListNode *current = list->head;
  138.    
  139.     while (current) {
  140.         ListNode *next = current->next;
  141.         
  142.         if (list->free_func) {
  143.             list->free_func(current->data);
  144.         }
  145.         
  146.         free(current);
  147.         current = next;
  148.     }
  149.    
  150.     list->head = NULL;
  151.     list->tail = NULL;
  152.     list->count = 0;
  153. }
  154. // 销毁链表
  155. void destroy_linked_list(LinkedList *list) {
  156.     if (list) {
  157.         clear_linked_list(list);
  158.         free(list);
  159.     }
  160. }
  161. // 整数比较函数
  162. int int_compare(const void *a, const void *b) {
  163.     return *(const int*)a - *(const int*)b;
  164. }
  165. // 字符串比较函数
  166. int string_compare(const void *a, const void *b) {
  167.     return strcmp((const char*)a, (const char*)b);
  168. }
  169. // 打印整数
  170. void print_int(void *data) {
  171.     printf("%d ", *(int*)data);
  172. }
  173. // 打印字符串
  174. void print_string(void *data) {
  175.     printf("%s ", (char*)data);
  176. }
  177. int main() {
  178.     // 创建整数链表
  179.     LinkedList *int_list = create_linked_list(default_free_func);
  180.     if (!int_list) {
  181.         printf("Failed to create integer list\n");
  182.         return 1;
  183.     }
  184.    
  185.     // 添加整数到链表
  186.     for (int i = 1; i <= 10; i++) {
  187.         int *num = (int*)malloc(sizeof(int));
  188.         if (!num) {
  189.             printf("Memory allocation failed\n");
  190.             destroy_linked_list(int_list);
  191.             return 1;
  192.         }
  193.         *num = i;
  194.         append_to_list(int_list, num);
  195.     }
  196.    
  197.     printf("Integer list: ");
  198.     traverse_list(int_list, print_int);
  199.     printf("\n");
  200.    
  201.     // 查找整数
  202.     int search_num = 5;
  203.     int *found = (int*)find_in_list(int_list, &search_num, int_compare);
  204.     if (found) {
  205.         printf("Found %d in the list\n", *found);
  206.     } else {
  207.         printf("%d not found in the list\n", search_num);
  208.     }
  209.    
  210.     // 删除整数
  211.     int remove_num = 3;
  212.     if (remove_from_list(int_list, &remove_num, int_compare) == 0) {
  213.         printf("Removed %d from the list\n", remove_num);
  214.     } else {
  215.         printf("Failed to remove %d from the list\n", remove_num);
  216.     }
  217.    
  218.     printf("Integer list after removal: ");
  219.     traverse_list(int_list, print_int);
  220.     printf("\n");
  221.    
  222.     // 创建字符串链表
  223.     LinkedList *str_list = create_linked_list(default_free_func);
  224.     if (!str_list) {
  225.         printf("Failed to create string list\n");
  226.         destroy_linked_list(int_list);
  227.         return 1;
  228.     }
  229.    
  230.     // 添加字符串到链表
  231.     char *strings[] = {"apple", "banana", "cherry", "date", "elderberry"};
  232.     for (int i = 0; i < 5; i++) {
  233.         char *str = strdup(strings[i]);
  234.         if (!str) {
  235.             printf("Memory allocation failed\n");
  236.             destroy_linked_list(int_list);
  237.             destroy_linked_list(str_list);
  238.             return 1;
  239.         }
  240.         append_to_list(str_list, str);
  241.     }
  242.    
  243.     printf("String list: ");
  244.     traverse_list(str_list, print_string);
  245.     printf("\n");
  246.    
  247.     // 查找字符串
  248.     char *search_str = "cherry";
  249.     char *found_str = (char*)find_in_list(str_list, search_str, string_compare);
  250.     if (found_str) {
  251.         printf("Found '%s' in the list\n", found_str);
  252.     } else {
  253.         printf("'%s' not found in the list\n", search_str);
  254.     }
  255.    
  256.     // 删除字符串
  257.     char *remove_str = "date";
  258.     if (remove_from_list(str_list, remove_str, string_compare) == 0) {
  259.         printf("Removed '%s' from the list\n", remove_str);
  260.     } else {
  261.         printf("Failed to remove '%s' from the list\n", remove_str);
  262.     }
  263.    
  264.     printf("String list after removal: ");
  265.     traverse_list(str_list, print_string);
  266.     printf("\n");
  267.    
  268.     // 销毁链表
  269.     destroy_linked_list(int_list);
  270.     destroy_linked_list(str_list);
  271.    
  272.     return 0;
  273. }
复制代码

5. 最佳实践

5.1 void类型使用的注意事项

在使用void和void*时,需要注意以下几点:

void*提供了极大的灵活性,但也牺牲了类型安全。在使用void*时,确保类型转换是正确的:
  1. // 不安全的类型转换
  2. void *ptr = malloc(sizeof(int));
  3. *(float*)ptr = 3.14;  // 错误:分配的是int大小的内存,但用作float
  4. // 安全的类型转换
  5. void *ptr = malloc(sizeof(float));
  6. *(float*)ptr = 3.14;  // 正确:分配和使用的类型一致
复制代码

在将void*转换为特定类型指针时,确保内存对齐是正确的:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdalign.h>
  4. // 安全的内存分配和类型转换
  5. void* safe_alloc(size_t size, size_t alignment) {
  6.     // 分配额外的空间以确保对齐
  7.     void *ptr = malloc(size + alignment - 1 + sizeof(void*));
  8.     if (!ptr) return NULL;
  9.    
  10.     // 计算对齐后的地址
  11.     void *aligned_ptr = (void*)(((uintptr_t)ptr + sizeof(void*) + alignment - 1) & ~(alignment - 1));
  12.    
  13.     // 存储原始指针以便后续释放
  14.     ((void**)aligned_ptr)[-1] = ptr;
  15.    
  16.     return aligned_ptr;
  17. }
  18. // 安全的内存释放
  19. void safe_free(void *ptr) {
  20.     if (ptr) {
  21.         free(((void**)ptr)[-1]);
  22.     }
  23. }
  24. int main() {
  25.     // 分配对齐的内存
  26.     int *int_ptr = (int*)safe_alloc(sizeof(int), alignof(int));
  27.     if (int_ptr) {
  28.         *int_ptr = 42;
  29.         printf("Aligned int value: %d\n", *int_ptr);
  30.         safe_free(int_ptr);
  31.     }
  32.    
  33.     // 分配对齐的double内存
  34.     double *double_ptr = (double*)safe_alloc(sizeof(double), alignof(double));
  35.     if (double_ptr) {
  36.         *double_ptr = 3.14159;
  37.         printf("Aligned double value: %f\n", *double_ptr);
  38.         safe_free(double_ptr);
  39.     }
  40.    
  41.     return 0;
  42. }
复制代码

5.2 避免常见错误

永远不要直接解引用void*指针,必须先将其转换为具体的类型指针:
  1. // 错误示例
  2. void *ptr = malloc(sizeof(int));
  3. *ptr = 42;  // 编译错误:不能解引用void指针
  4. // 正确示例
  5. void *ptr = malloc(sizeof(int));
  6. *(int*)ptr = 42;  // 正确:先转换为int指针
复制代码

不要直接对void*进行算术运算,必须先将其转换为具体的类型指针:
  1. // 错误示例
  2. void *ptr = malloc(10 * sizeof(int));
  3. ptr++;  // 编译错误:不能对void指针进行算术运算
  4. // 正确示例
  5. void *ptr = malloc(10 * sizeof(int));
  6. int *int_ptr = (int*)ptr;
  7. int_ptr++;  // 正确:先转换为int指针
复制代码

在C语言中,void func()和void func(void)是不同的:
  1. // 在C语言中:
  2. void func();    // 可以接受任意数量和类型的参数(旧式C语法)
  3. void func(void); // 不接受任何参数
  4. // 在C++中,两者等价,都表示不接受参数
复制代码

5.3 性能考虑

频繁的类型转换会影响性能,应尽量减少不必要的转换:
  1. // 性能较差:多次类型转换
  2. void process_data(void *data, int count) {
  3.     for (int i = 0; i < count; i++) {
  4.         ((int*)data)[i] *= 2;  // 每次循环都进行类型转换
  5.     }
  6. }
  7. // 性能较好:一次性类型转换
  8. void process_data_optimized(void *data, int count) {
  9.     int *int_data = (int*)data;  // 一次性类型转换
  10.     for (int i = 0; i < count; i++) {
  11.         int_data[i] *= 2;
  12.     }
  13. }
复制代码

对于频繁使用的类型转换操作,可以使用内联函数:
  1. // 使用内联函数进行类型转换
  2. static inline void* int_to_void(int *ptr) {
  3.     return (void*)ptr;
  4. }
  5. static inline int* void_to_int(void *ptr) {
  6.     return (int*)ptr;
  7. }
  8. // 使用示例
  9. void process_data(int *data, int count) {
  10.     void *void_ptr = int_to_void(data);
  11.    
  12.     // 一些使用void_ptr的操作...
  13.    
  14.     int *int_ptr = void_to_int(void_ptr);
  15.     for (int i = 0; i < count; i++) {
  16.         int_ptr[i] *= 2;
  17.     }
  18. }
复制代码

5.4 代码可读性与维护性

使用typedef为复杂的函数指针类型定义别名,提高代码可读性:
  1. // 不易读的函数指针声明
  2. void register_callback(void (*callback)(void*, int), void *data);
  3. // 更易读的typedef方式
  4. typedef void (*CallbackFunc)(void*, int);
  5. void register_callback(CallbackFunc callback, void *data);
复制代码

为void*参数添加注释,说明预期的数据类型:
  1. /**
  2. * @brief 处理整数数组数据
  3. * @param data 指向整数数组的void指针
  4. * @param count 数组元素个数
  5. */
  6. void process_int_array(void *data, int count) {
  7.     int *array = (int*)data;
  8.     // 处理数组...
  9. }
复制代码

将void*操作封装在函数中,提高代码的模块化和可维护性:
  1. // 封装void指针操作
  2. typedef struct {
  3.     void *data;
  4.     size_t size;
  5.     size_t capacity;
  6. } GenericBuffer;
  7. // 创建通用缓冲区
  8. GenericBuffer* create_buffer(size_t initial_capacity) {
  9.     GenericBuffer *buffer = (GenericBuffer*)malloc(sizeof(GenericBuffer));
  10.     if (!buffer) return NULL;
  11.    
  12.     buffer->data = malloc(initial_capacity);
  13.     if (!buffer->data) {
  14.         free(buffer);
  15.         return NULL;
  16.     }
  17.    
  18.     buffer->size = 0;
  19.     buffer->capacity = initial_capacity;
  20.    
  21.     return buffer;
  22. }
  23. // 向缓冲区添加数据
  24. int buffer_append(GenericBuffer *buffer, void *data, size_t data_size) {
  25.     if (!buffer || !data) return -1;
  26.    
  27.     // 检查是否有足够的空间
  28.     if (buffer->size + data_size > buffer->capacity) {
  29.         // 扩展缓冲区
  30.         size_t new_capacity = buffer->capacity * 2;
  31.         while (buffer->size + data_size > new_capacity) {
  32.             new_capacity *= 2;
  33.         }
  34.         
  35.         void *new_data = realloc(buffer->data, new_capacity);
  36.         if (!new_data) return -1;
  37.         
  38.         buffer->data = new_data;
  39.         buffer->capacity = new_capacity;
  40.     }
  41.    
  42.     // 复制数据
  43.     memcpy((char*)buffer->data + buffer->size, data, data_size);
  44.     buffer->size += data_size;
  45.    
  46.     return 0;
  47. }
  48. // 获取缓冲区数据
  49. void* buffer_data(GenericBuffer *buffer) {
  50.     return buffer ? buffer->data : NULL;
  51. }
  52. // 获取缓冲区大小
  53. size_t buffer_size(GenericBuffer *buffer) {
  54.     return buffer ? buffer->size : 0;
  55. }
  56. // 销毁缓冲区
  57. void destroy_buffer(GenericBuffer *buffer) {
  58.     if (buffer) {
  59.         free(buffer->data);
  60.         free(buffer);
  61.     }
  62. }
  63. // 使用示例
  64. int main() {
  65.     // 创建缓冲区
  66.     GenericBuffer *buffer = create_buffer(1024);
  67.     if (!buffer) {
  68.         printf("Failed to create buffer\n");
  69.         return 1;
  70.     }
  71.    
  72.     // 添加整数数据
  73.     int int_data[] = {10, 20, 30, 40, 50};
  74.     buffer_append(buffer, int_data, sizeof(int_data));
  75.    
  76.     // 添加字符串数据
  77.     char str_data[] = "Hello, world!";
  78.     buffer_append(buffer, str_data, strlen(str_data) + 1);
  79.    
  80.     // 使用缓冲区数据
  81.     int *int_ptr = (int*)buffer_data(buffer);
  82.     char *str_ptr = (char*)buffer_data(buffer) + sizeof(int_data);
  83.    
  84.     printf("Integer data: %d, %d, %d\n", int_ptr[0], int_ptr[1], int_ptr[2]);
  85.     printf("String data: %s\n", str_ptr);
  86.    
  87.     // 销毁缓冲区
  88.     destroy_buffer(buffer);
  89.    
  90.     return 0;
  91. }
复制代码

结论

在Linux系统开发中,void和void*是强大的工具,它们提供了高度的灵活性和抽象能力。通过本文的探讨,我们了解了void类型的基础概念、使用场景、实际案例以及高级开发技巧和最佳实践。

正确使用void和void*可以帮助我们实现:

• 通用接口和API
• 高度抽象的数据结构
• 灵活的回调机制
• 高效的内存管理

然而,这种灵活性也带来了类型安全的挑战。因此,在使用void和void*时,我们需要遵循最佳实践,确保代码的安全性、可读性和可维护性。

通过深入理解void和void*在Linux系统开发中的应用,我们可以编写出更加灵活、高效和可维护的代码,充分发挥Linux系统的强大功能。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则