【问题标题】:Meaning of returns char when return value is void, and gets an void argument?返回值为 void 时返回 char 的含义,并得到一个 void 参数?
【发布时间】:2020-09-26 22:44:03
【问题描述】:

我正在学习使用 C 进行线程化,我对给出的示例有点困惑。他们声明了一个函数print_name,其返回值为void,但随后它返回了一个字符串——如何以及为什么?函数print_name 接受一个名为name 的参数,但它是void 的指针; void 类型的变量是什么意思,它如何接受字符串?

ma​​in.c

#include <stdio.h> // I-O
#include <pthread.h> // threading

void *print_name(void *name)
{
    puts(name);

    return name;
}

int main(int argc, char const *argv[])
{
    pthread_t thread_id;
    pthread_create(&thread_id, NULL, print_name, "ha ones be eilat");

    pthread_join(thread_id, NULL);
    return 0;
}

使用gcc编译和运行

$ cc main.c -o main -Wall -pthread && ./main
ha ones be eilat

【问题讨论】:

  • 不是void,而是void *。
  • @AnttiHaapala Wdym,在哪里?

标签: c


【解决方案1】:

参数类型和返回类型不是void,而是指向void的指针。

在 C 中,通过 return 语句传递和返回值的参数都像赋值一样发生。 void * 是一种通用指针类型,与 void * 和其他指针类型的转换将隐式发生,即没有 cast。

作为char 数组的字符文字衰减为char *,并隐式转换为void * 以匹配pthread_create 的原型。 void * 隐式转换为 char * 以匹配 puts 的原型。

print_name 具有原型void * print_name(void *),因此指向该函数 的指针将匹配pthread_create 所期望的类型(第三个参数是void *(*start_routine) (void *)。)

pthread_create的声明是

int pthread_create(
    pthread_t *thread,
    const pthread_attr_t *attr,
    void *(*start_routine) (void *), 
    void *arg
);

【讨论】:

  • 哦,转换为 void * 以匹配 pthread_create 的原型。现在我明白了,谢谢。
【解决方案2】:

void * 类型是一个“通用指针”,可以指向任何对象类型。 (在许多(但不是全部)机器上,void * 也可以保存一个函数指针——然而,这与这个问题无关。)在 C 中,任何对象指针都可以转换为 void * 并返回到原始类型没有变化。使用void * 可能很危险;它可能非常有用(并且线程创建可以显示出危险性和有用性)。

与问题中的声明相反,函数 print_name() 被定义为返回 void * 值并接受 void * 参数。 pthread_create() 函数需要一个(指向一个)与签名匹配的线程函数:

void *thread_function(void *);

这就是传递给它的内容。由于该函数返回void *,因此返回它传递的指针是合法的,尽管这实际上是不寻常的事情。

可以通过向pthread_join() 传递一个适当的非NULL 指针来收集线程函数的返回值;该示例并未证明这一点。

void *result;
if (pthread_join(thread_id, &result) == 0)
    printf("Result: <<%s>>\n", result);

在示例中,这将在一行上打印Result: &lt;&lt;ha ones be eilat&gt;&gt;。很多时候,您会将返回的指针转换为显式的非void 指针——例如char *str = result; — 然后使用它。

请注意,C 中没有任何内容可以阻止您调用:

int i = 0;
if (pthread_create(&thread_id, NULL, print_name, &i) != 0)
    …thread creation failed…

传递了错误类型的数据,但编译器会将其视为正常。在运行时,如果您(不)幸运,将打印一个空行,但是当您将int * 传递给需要char * 才能正常工作的函数时,一切皆有可能(由于未定义的行为) .无法检查类型是void * 的弱点,但它也是一个优势,因为它允许pthread_create() 函数将指向任何类型数据的指针传递给函数。程序员有责任获得正确的类型——被调用的函数必须期望将void * 参数转换为指向真正传递的类型的指针。此外,通过指针传递给函数的数据需要稳定——如果启动另一个线程,则不会更改。无法保证线程读取传递的数据的顺序。在调用pthread_create() 之间传递指向结构的指针并更改结构中的值是不行的。与返回值类似。那里还有一些额外的皱纹。指向的数据必须在函数退出后才有效,所以不能是局部变量。

【讨论】:

    猜你喜欢
    • 2017-07-13
    • 2016-08-28
    • 1970-01-01
    • 1970-01-01
    • 2023-01-28
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多