1. 问题来源
thrd_create() 函数功能为新建一个线程,传入待执行的函数。待执行函数的格式要求如下:
typedef int (*thrd_start_t)(void *arg);
这意味着待执行函数只能返回 int 类型值,接收 void* arg 参数。若待执行函数想要返回一个结构体,该如何操作?
2. 解决方案
解决方案一:由于返回值为 int 类型,指针的本质也是一串数字,所以可将结构体指针进行返回,从而返回结构体。
#include <stdio.h>
#include <tinycthread.h>
#include <stdlib.h>
// 待返回的结构体
typedef struct {
int a;
char *b;
} ComplexResult;
int ComplexReturnValue(void *arg){
ComplexResult *complex_result = malloc(sizeof(ComplexResult));
complex_result->a = 1;
complex_result->b = "hello";
return complex_result; // 返回结构体指针
}
void TestComplexReturn(){
thrd_t t;
thrd_create(&t, ComplexReturnValue, NULL);
int result;
thrd_join(t, &result);
ComplexResult *complex_result = (ComplexResult *)result; // 函数结果强转为结构体指针类型
printf("complex_result->a: %d\n", complex_result->a);
printf("complex_result->a: %s\n", complex_result->b);
}
注意,在 ComplexReturnValue() 函数中使用 malloc 创建结构体指针,而不是新建 ComplexResult 结构体。原因在于新建的结构体存储在函数栈上,一旦函数退出,结构体的内存会被释放。使用 malloc 创建的结构体指针,其指向的结构体存储在堆区中,不会随着函数退出而释放,需要使用 free() 主动释放(https://blog.csdn.net/gltzlike/article/details/114649846)。
在 32 位 msvc 编译器下运行结果无误,而在 64 位 msvc 编译器下运行出错。原因在于指针类型和 int 类型的强制转换,32 位系统下指针类型大小为 4 个字节,与 int 类型大小相同,所以程序可正常运行。64 位系统下指针类型大小通常为 8 个字节,强转为 int 类型会出错,故程序执行错误。
解决方案二:函数返回值的设置是为了获取到被函数修改后的变量。将指针作为函数参数,在函数执行过程中对指针指向的内容进行更改,从而实现与函数返回值相同的功能。例如:
void change(int *temp){
*temp = 4;
}
void Test(){
int a = 2;
int *p = &a;
change(p);
printf("a: %d\n", a); // a: 4
}
同理,将结构体指针作为函数参数,在函数执行过程中对结构体相关内容进行更改,其功能和返回结构体相同。由于对结构体指针进行操作,即直接对内存进行操作,所以结构体相关的变量可以直接被修改。
#include <stdio.h>
#include <tinycthread.h>
#include <stdlib.h>
typedef struct {
int a;
char *b;
} ComplexResult;
int ComplexReturnValue(ComplexResult *arg){
ComplexResult *complex_result = arg;
complex_result->a = 1;
complex_result->b = "hello";
return 0;
}
void TestComplexReturn(){
thrd_t t;
// ComplexResult *complex_result = malloc(sizeof(ComplexResult));
ComplexResult complex_result;
thrd_create(&t, ComplexReturnValue, &complex_result);
int result;
thrd_join(t, &result);
printf("complex_result->a: %d\n", complex_result.a);
printf("complex_result->b: %s\n", complex_result.b);
}
3. 总结
函数若要返回复杂的返回值(例如结构体),解决方法之一便是利用函数参数解决。解决方法之二是使用函数回调,见下一小节。