In studying uthreads (from pthreads), I have come across the following line of code:
uthread_t uthread_create (void* (*start_proc)(void*), void* start_arg)
I am not sure what uthread_create() is taking as the first parameter. Is it taking pointer to no specific type casted to pointer to type start_proc? Can someone clarify?
The first argument is a function pointer. start_proc points to a function that takes a single void * parameter and returns a void *, which in this case is the entry point for a thread. Also, the second argument to uthread_create is the parameter which will get passed to start_proc when it is called.
A function like this would satisfy the function pointer:
void *my_thread(void *p)
{
char *s = p;
printf("s=%s", s);
return NULL;
}
And you could call uthread_create like this:
uthread_t tid;
char str[] = "test string";
tid = uthread_create(my_thread, str);
Related
This might be a bit specific, but I want to know, how to return a ... let's see the code first actually.
void *atomic_op(void * (*f)(),void* ret) // Using a function pointer to encapsulate the procedure in between locks
{
pthread_mutex_lock(&mut1);
ret = f;
pthread_mutex_unlock(&mut1);
}
I want to be able to get the return value of f and store it to ret using void pointers for more general use.
My IDE informs me that argument ret is not accessed outside the scope of this function, but later down my code there is
char* temp;
while (1)
{
atomic_op(readBuffer(shared_array),temp);
if (*temp == 0)
{
break;
}
atomic_op(printOutBuffer(shared_array),NULL);
}
When running the whole thing, the IDE comes our right (of course) but I cannot understand why.
The whole thing is an attempt on monitors, with 2 threads sharing an array in a consumer producer relationship (just experimenting) and I stumbled across this which I found really weird!
Can someone explain what happens here?
The whole thing is here https://controlc.com/2af8f50c
Link with pthread
First off, this doesn't actually call the function:
ret = f;
It just takes the function pointer and assigns it to ret. To call the function you want f().
Also, because parameters in C are passed by value, changes to the parameter ret aren't reflected in the calling function. That fact that ret is a pointer type doesn't matter.
If you want a function to update a pointer value it needs to take a pointer to a pointer. That pointer-to-pointer parameter must then be dereferenced to update the pointer variable in the calling function.
Making these fixes, your function would look like this:
void *atomic_op(void * (*f)(),void **ret)
{
pthread_mutex_lock(&mut1);
if (ret) {
*ret = f();
}
pthread_mutex_unlock(&mut1);
}
And you would call it like this:
char *tmp;
void *tmp2;
atomic_op(readBuffer(shared_array),&tmp2);
tmp = tmp2;
Here the extra void * variable is required because a char ** is not guaranteed to be safely converted to a void **.
There's still one thing we haven't addressed, and that's that the function is defined to return a void * but doesn't actually return anything. This is OK for your program since you're not attempting to access the return value, but still it's a bad code smell.
It would be better to take the return value of f and make that the return value of atomic_op and get rid of the second parameter. This also means you don't need a second variable in the calling function.
So now we have:
void *atomic_op(void * (*f)())
{
void *ret;
pthread_mutex_lock(&mut1);
ret = f();
pthread_mutex_unlock(&mut1);
return ret;
}
Which would be called like this:
char *tmp;
tmp = atomic_op(readBuffer(shared_array));
All this is assuming that readBuffer and printOutBuffer return function pointers. If they don't, you need to pass just the name of the function and the function's parameters to atomic_op, and the type of f would need to match the type of readBuffer and printOutBuffer. That would give you:
void *atomic_op(void *(*f)(void *), void *param)
{
void *ret;
pthread_mutex_lock(&mut1);
ret = f(param);
pthread_mutex_unlock(&mut1);
return ret;
}
Which is called like this:
char *tmp;
tmp = atomic_op(readBuffer, shared_array);
I am learning about threading with C, and I'm a bit confused about the example given. They declared a function print_name with return value of void, but then it returns a string — how and why? The function print_name accepts one argument which is called name but it is a pointer of void; what does a variable of type void mean, and how can it accept a string?
main.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;
}
To compile and run with gcc
$ cc main.c -o main -Wall -pthread && ./main
ha ones be eilat
The argument type and return type is not void but pointer to void.
In C both argument passing and returning a value with the return statement happen as if by assignment. void * is a generic pointer type and conversions to and from void * from and to other pointer types will happen implicitly, i.e. without a cast.
The character literal which is an array of char decays to char * and is implicitly converted to void * to match the prototype of pthread_create. The void * is implicitly converted to char * to match the prototype of puts.
print_name has prototype void * print_name(void *) so that a pointer to that function will match the type expected by pthread_create (The third parameter is void *(*start_routine) (void *).)
The declaration of pthread_create is
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg
);
The type void * is a 'universal pointer' that can point to any object type. (On many, but not all, machines, a void * can also hold a function pointer — however, that's tangential to this question.) In C, any object pointer can be converted to a void * and back to the original type without change. Using void * can be dangerous; it can be extremely useful (and thread creation can show both dangerousness and usefulness).
Contrary to the claim in the question, the function print_name() is defined to return a void * value as well as accept a void * argument. The pthread_create() function expects a (pointer to a) thread function that matches the signature:
void *thread_function(void *);
And that's what is passed to it. Since the function returns a void *, it is legitimate to return the pointer it was passed, though that is actually an unusual thing to do.
The return value from the thread function can be collected by passing an appropriate, non-NULL pointer to pthread_join(); the example does not demonstrate that.
void *result;
if (pthread_join(thread_id, &result) == 0)
printf("Result: <<%s>>\n", result);
This would, in the example, print Result: <<ha ones be eilat>> on a line. Many times, you'd convert the returned pointer to an explicit non-void pointer — e.g. char *str = result; — and then use that.
Note that there is nothing in C that would stop you calling:
int i = 0;
if (pthread_create(&thread_id, NULL, print_name, &i) != 0)
…thread creation failed…
The wrong type of data is passed, but that will be treated as OK by the compiler. At run-time, if you're (un)lucky, an empty line will be printed, but anything is possible (because of undefined behaviour) as you passed an int * to a function that requires a char * to work correctly. This inability to check types is a weakness of void *, but it is also a strength as it allows the pthread_create() function to pass a pointer to any type of data to a function. The onus is on the programmer to get the types right — the called function must expect to convert the void * parameter to a pointer to the type that was really passed. Also, the data passed via the pointer to the function needs to be stable — not changed if another thread is started. There is no guarantee about the order in which threads will read the data passed. Passing a pointer to a structure and changing the value in the structure between calls to pthread_create() is a no-no. Similarly with the return value. There are some additional wrinkles there. The data pointed at must be valid after the function exits, so it can't be a local variable.
I'm new to C and im currently learning about pointers.
I'm not sure why I am getting an error with the following sections of code in regards to pointers :
char ch;
char** pointer;
pointer = &ch;
and
int function1(void)
{
return 42.0;
}
void function2(void)
{
void (*pointer)(int);
pointer = &function1;
...
}
Any help will be appreciated :)
The very first problem is that you are using a double pointer in char** pointer ,as you are not storing the address of some other pointer so you should use char *pointer instead.
Then your function1 has return type as int but you are returning a float value ,although it won't give you any error but it can create some logical issues in your program,so better to properly write the return type in function definition and its prototype.
Then the next problem is in the function2,your function1 returns int but does not take any arguments but your function pointer return void and take int ,so you should better modify this to
int (*pointer)(void);
and then store the address of function1 in pointer ,it will work fine.
* is a single pointer and ** is a pointer to pointer.
So instead of
char** pointer;
It should be:
char* pointer;
In the second case, the function pointer prototype is not matching the prototype of the function it is pointing to.
So instead of
void (*pointer)(int);
it should be:
int (*pointer)(void);
you second section have some mistakes
you function1() return int and not take args
but your fucntion ptr return void and take int
so change it to:
int (*pointer)(void);
pointer = &function1;
I have a problem in C. I have this function :
int test(void *data);
I want to change data with this function but I don't want another prototype (not use void **). Actualy, data equals null out this function.
#include <stdio.h>
#include <stdlib.h>
int
test(void *data)
{
data = "toto";
return 1;
}
int
main()
{
void *d;
if (test(d) != 1) {
printf("erreur\n");
}
printf("résultat : %s\n", (char *) d); // displays "résultat : (null)"
return 0;
}
Help me please. ;)
In C arguments to function are passed by value. d is passed by value to function test. data is a local variable to function test and d is copied to data. The assignment
data = "toto";
makes pointer data to point to string literal toto, while d is unaffected of this assignment in main function. So, this assignment has no effect on d.
In main you are dereferencing an uninitialized pointer. This will result in undefined behavior.
In your test function, you change data, which doesn't affect d because data is just a local variable. If you really need to change d, then you need to let test return data and do d=test(d).
Moreover, in your test function, the value of data is never used. So what is the point to have data as a parameter of the function?
In printf("résultat : %s\n", (char *) d);, you try to cast d into pointer to char and then print the value of d. Although you don't dereference d, you are still printing a variable that hasn't been initialized, which is undefined behavior.
Any object pointer (i.e. non-function pointer) can be converted to a void * and back to the original type without altering the value. This means that you can pass any kind of (object) pointer to your test() function, it will be automatically converted to a void *, and you can then convert it back inside test().
#include <stdio.h>
int test(void *data)
{
char **s = data;
*s = "toto";
return 1;
}
int main()
{
char *res;
if (test(&res) != 1) {
printf("erreur\n");
}
printf("résultat : %s\n", res);
return 0;
}
You just need to make sure that the test() function knows what the original type was.
void (*a)(char*, char*);
is this a function called a. returns void pointer?
in c?
This is a function pointer named a. The function signature of a is a function that returns void and takes two char * arguments.
See Function Pointer Tutorials for more information on function pointers.
It's a pointer to a function, which takes 2x char pointers & returns void (see cdecl.org)
It is a function pointer. Example:
void someFunction(char* param1, char* param2) {
// ...
}
int main(int argc, char* argv[]) {
char arg1[] = "Hello";
char arg2[] = "World";
void (*a)(char*, char*) = &someFunction;
a(arg1, arg2);
return 0;
}
This is declaration of a variable named a; it is a pointer to a function that takes two char* parameters and does not return anything. You will need to assign an actual function to a before calling it.
It's a variable which is a pointer to a function returning nothing, which takes two arguments of type "pointer to char". The function pointer is named "a".
No.
It is a pointer to a function that takes two strings and returns nothing.