简体   繁体   中英

How can I mask the warning from makecontext if the function passed in has parameters?

When using the function, makecontext , from <ucontext_t.h> in C, it takes the arguments (ucontext_t* context, void (*someFunction)(void), int numberOfArguments, ...) . The numberOfArguments is to pass in arguments into someFunction , but when passing in arguments, I get compile warnings.

I need to, or should, remove these since this is for a school project and warnings may make me lose points. I think I'm allowed to edit the flags of the Makefile, but I'd prefer to adjust the code.

I did 2 tests.

1 : Passed a function and string as arguments

The code for test1 is:

#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;
}

My output for test1 is:

$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 : Passed an int as argument

The code for test2 is:

#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;
}

My output for test2 is:

$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

The parameter someFunction is of type void(*)(void) , which requires to be passed a pointer to a function that takes no arguments and returns void (not void * )

You can arrange for it to work, changing the definition of someFunction into something like:

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

Int this case, the compiler will accept any function that returns void * , but then you have to double check that the function you pass has the proper number and types of arguments. This is called an incomplete type definition, and it is very error prone (it is conserved from ancient C, long time before the ANSI revision)

if you want a function that takes a void * argument and returns a void * result, change the definition of someFunction to:

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

But if this is an academic exercise, I suggest you to do full type checking, and don't try to use the C facilities to make mistakes :) (they require you know very well what you are doing)

In your case, the helper function requires an int parameter, which is not a void * (indeed, most probably they are not even the same size) so the body of the makecontext function will not be able to call it correctly. The compiler is there to protect you from yourself.

This is actually a mistake pointed out in this manual of makecontext() :

With the incorporation of the ISO/IEC 9899:1999 standard into this specification it was found that the ISO C standard (Subclause 6.11.6) specifies that the use of function declarators with empty parentheses is an obsolescent feature. Therefore, using the function prototype:

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

is making use of an obsolescent feature of the ISO C standard. Therefore, a strictly conforming POSIX application cannot use this form. Therefore, use of getcontext(), makecontext(), and swapcontext() is marked obsolescent.

A usual workaround is to use a cast. To make it, define a new type:

typedef void (* ucfunc_t)(void);

Then you use this definition to cast the parameter passed to 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM