0

当使用 C 中的函数 ,makecontext<ucontext_t.h>,它需要参数(ucontext_t* context, void (*someFunction)(void), int numberOfArguments, ...)numberOfArguments是将参数传递给,someFunction但是在传递参数时,我会收到编译警告。

我需要或应该删除这些,因为这是针对学校项目的,警告可能会让我丢分。我想我可以编辑 Makefile 的标志,但我更愿意调整代码。

我做了2次测试。

1:传递一个函数和字符串作为参数

test1 的代码是:

#include <stdio.h>
#include <ucontext.h>

// Outputs arg as a string
void* f(void* arg) {
    printf("%s\n", (char*)arg);
    return 0; // Returns back to c0
}

// makecontext takes as argument2, (void (*)(void)), but allows (void (*)(...))
// I want to remove the warning from using (void (*)(...))
void helper(void* (*selectFunction)(void*), void* selectArg) {
    // Calls select function with select argument
    selectFunction(selectArg);
}

int main()
{
    // Initialize contexts
    ucontext_t c0, c1;
    char stack[1024];

    getcontext(&c1);
    // Setup stack for c1
    c1.uc_stack.ss_sp = stack;
    c1.uc_stack.ss_size = sizeof(stack);
    c1.uc_link = &c0; // Swap to c0 stack on c1 stack end

    void* (*selectFunction)(void*) = &f;
    void* selectArg = (void*)("abc123 testing testing");

    // Passes function f with arg "abc123 testing testing" to helper
    makecontext(&c1, helper, 2, selectFunction, selectArg);

    // Swap to context that calls function helper
    swapcontext(&c0, &c1);

    printf("Welcome back\n");

    return 0;
}

我对 test1 的输出是:

$gcc -o main *.c
main.c: In function ‘main’:
main.c:33:22: warning: passing argument 2 of ‘makecontext’ from incompatible pointer type [-Wincompatible-pointer-types]
     makecontext(&c1, helper, 2, selectFunction, selectArg);
                      ^~~~~~
In file included from main.c:2:0:
/usr/include/ucontext.h:47:13: note: expected ‘void (*)(void)’ but argument is of type ‘void (*)(void * (*)(void *), void *)’
 extern void makecontext (ucontext_t *__ucp, void (*__func) (void),
             ^~~~~~~~~~~
$main
abc123 testing testing
Welcome back

2 : 传递一个 int 作为参数

test2 的代码是:

#include <stdio.h>
#include <ucontext.h>

// Outputs arg as a string
void f(int n) {
    printf("%d\n", n);
    return; // Returns back to c0
}

// makecontext takes as argument2, (void (*)(void)), but allows (void (*)(...))
// I want to remove the warning from using (void (*)(...))
void helper(int arg) {
    // Calls f with arg
    f(arg);
}

int main()
{
    // Initialize contexts
    ucontext_t c0, c1;
    char stack[1024];

    getcontext(&c1);
    // Setup stack for c1
    c1.uc_stack.ss_sp = stack;
    c1.uc_stack.ss_size = sizeof(stack);
    c1.uc_link = &c0; // Swap to c0 stack on c1 stack end

    // Make a context to run f with argument 5
    makecontext(&c1, helper, 1, 5);

    // Swap to context that calls function helper
    swapcontext(&c0, &c1);

    printf("Welcome back\n");

    return 0;
}

我对 test2 的输出是:

$gcc -o main *.c
main.c: In function ‘main’:
main.c:30:22: warning: passing argument 2 of ‘makecontext’ from incompatible pointer type [-Wincompatible-pointer-types]
     makecontext(&c1, helper, 1, 5);
                      ^~~~~~
In file included from main.c:2:0:
/usr/include/ucontext.h:47:13: note: expected ‘void (*)(void)’ but argument is of type ‘void (*)(int)’
 extern void makecontext (ucontext_t *__ucp, void (*__func) (void),
             ^~~~~~~~~~~
$main
5
Welcome back
4

2 回答 2

1

参数someFunction是 type void(*)(void),需要传递一个指向不带参数并返回void(not void *)的函数的指针

您可以安排它工作,将定义更改为someFunction

void *(*someFunction)()  /* don't specify the argument list */

在这种情况下,编译器将接受任何返回的函数void *,但是您必须仔细检查您传递的函数是否具有正确数量和类型的参数。这被称为不完整的类型定义,并且非常容易出错(它是从古代 C 中保留下来的,在 ANSI 修订之前很久)

如果您想要一个接受void *参数并返回void *结果的函数,请将定义更改someFunction为:

void *(*someFunction)(void *), ...

但是如果这是一个学术练习,我建议你做完整的类型检查,不要试图使用 C 工具来犯错误:)(它们要求你非常清楚自己在做什么)

在您的情况下,辅助函数需要一个int参数,该参数不是 a void * (实际上,它们很可能甚至不是相同的大小),因此makecontext函数的主体将无法正确调用它。编译器可以保护您免受自己的伤害。

于 2020-03-10T16:34:50.983 回答
1

这实际上是本makecontext()手册中指出的错误:

随着 ISO/IEC 9899:1999 标准并入本规范,发现 ISO C 标准(子条款 6.11.6)规定使用带空括号的函数声明符已过时。因此,使用函数原型:

void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);

正在利用 ISO C 标准的过时特性。因此,严格符合 POSIX 的应用程序不能使用这种形式。因此,getcontext()、makecontext() 和 swapcontext() 的使用被标记为过时。

通常的解决方法是使用演员表。为此,定义一个新类型:

typedef void (* ucfunc_t)(void);

然后你使用这个定义来转换传递给makecontext()的参数:

#include <stdio.h>
#include <ucontext.h>

typedef void (* ucfunc_t)(void);

// Outputs arg as a string
void* f(void* arg) {
    printf("%s\n", (char*)arg);
    return 0; // Returns back to c0
}

// makecontext takes as argument2, (void (*)(void)), but allows (void (*)(...))
// I want to remove the warning from using (void (*)(...))
void helper(void* (*selectFunction)(void*), void* selectArg) {
    // Calls select function with select argument
    selectFunction(selectArg);
}

int main()
{
    // Initialize contexts
    ucontext_t c0, c1;
    char stack[1024];

    getcontext(&c1);
    // Setup stack for c1
    c1.uc_stack.ss_sp = stack;
    c1.uc_stack.ss_size = sizeof(stack);
    c1.uc_link = &c0; // Swap to c0 stack on c1 stack end

    void* (*selectFunction)(void*) = &f;
    void* selectArg = (void*)("abc123 testing testing");

    // Passes function f with arg "abc123 testing testing" to helper
    makecontext(&c1, (ucfunc_t)helper, 2, selectFunction, selectArg);

    // Swap to context that calls function helper
    swapcontext(&c0, &c1);

    printf("Welcome back\n");

    return 0;
}
于 2021-01-18T14:37:29.143 回答