Translating GPOINTER_TO_INT and GINT_TO_POINTER to plain C I get:
#include <stdio.h>
#include <stdlib.h>
void *fn(void *v)
{
int *i;
i = malloc(sizeof(int));
*i = (int)(long)v;
return i;
}
int main(void)
{
int *i = fn((void *)(long)10);
printf("%d\n", *i);
free(i);
return 0;
}
Is it portable?
Why the cast to long?
In GTK is used for callbacks e.g.:
#define FLAG 10
static void panel_set_handler(GtkWidget *widget, gpointer data)
{
panel_set(GPOINTER_TO_INT(data));
}
g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_set_handler), GINT_TO_POINTER(FLAG));
Solution 1: casts
The simplest, Just cast to and from intptr_t. It's the correct version of what the GLib macros do.
Solution 2: using the heap
If you have something bigger than an intptr_t, or when you're not confident in sizes, you can use a dynamically-allocated memory pointer, without casts this time:
void* ToHeap(void const *data, size_t dataSize)
{
void* ret = malloc(dataSize);
if(ret != NULL)
memcpy(ret, data, dataSize);
return ret;
}
int FromHeap(void* heapPtr, void *data, size_t dataSize)
{
int ret = 0;
if(heapPtr != NULL)
{
memcpy(data, heapPtr, dataSize);
free(heapPtr);
ret = 1;
}
return ret;
}
Here is a wrapper for use with ints:
void* IntToHeap(int i)
{
return ToHeap(&i, sizeof(int));
}
int IntFromHeap(void*heapPtr, int defaultValue)
{
int ret;
if(!FromHeap(heapPtr, &ret, sizeof(int))
ret = defaultValue;
return ret;
}
And you can use this that way:
#define FLAG 10
static void panel_set_handler(GtkWidget *widget, gpointer data)
{
panel_set(IntFromHeap(data, 0));
}
g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_set_handler), IntToHeap(FLAG));
That way is a bit like your post, minus all these casts.
Related
I want to perform a simple task working with function pointers in C.
The task is to get an array (from any type, i.e: int / char*), and sum /concatenate each 2 elements in the array.
for the char* type, it works fine, but for the int type, the loop seems to jump each 2 elements in the array (and thus overflow the array):
#define N1 4
#define N2 4
typedef void*(*Fn_Sum)(void*, void*);
typedef void(Fn_Prt)(void*);
int sum_num(int a, int b){
return a + b;
}
char* sum_char(char* a, char* b){
char *result = malloc(strlen(a) + strlen(b) + 1);
if (!result) {
printf("ERROR: malloc failed !\n");
return NULL;
}
strcpy(result, a);
strcat(result, b);
return result;
}
void print_num(int a){
printf("%d", a);
}
void print_string(char* a){
int i = 0;
while (a[i] != '\0') {
printf("%c", a[i]);
i++;
}
}
void PrintSums(void** P, int n, Fn_Sum fsum, Fn_Prt fprt){
for(int i = 0; i < n - 1; i++){
(fprt)(fsum(P[i], P[i+1]));
printf(", ");
}
printf("\n");
}
int main() {
int V[N1] = {1,2,3,4};
char* S[N2] = {"a", "d", "c", "d"};
PrintSums(V, N1, sum_num, print_num);
PrintSums(S, N2, sum_char, print_string);
return 0;
}
expected output is :
3, 5, 7,
ab, bc, cd,
actual outputs:
4, 725939, 4925336,
ad, dc, cd,
Create an abstract interface for iterator over the elements. A draft of such interface could look like this:
struct iterator {
...
};
// ptr - a pointer to beginning of the array
// size - size of one element in the array
void it_init(iterator *t, void *ptr, size_t size);
bool it_eq(iterator *t, iterator *o); // compare iteratores
void it_add(iterator *t, size_t n);
void it_inc(iterator *t);
// return a pointer to the element
void *it_get(iterator *t);
Remember to always pass to user callbacks a context variables. Otherwise users will have to use global variables, which make code messy. Create an abstract interface with destructors and constructors of your summing object. Handle errors properly:
// is passed a pointer to user context
// returns 0 on success
typedef int (*Fn_Sum)(void*, void*);
// is passed a pointer to user context
// returns 0 on success
typedef int (Fn_Prt)(void*);
// returns 0 on success
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx);
After that, implement objects that expose the interface that you want:
struct num { .. };
void num_sum(struct num *t, int el);
void num_print(struct num *t, int el);
// expose interface to PrintSums
// that just calls internal api
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
An example whole program looks like this:
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// iterator
typedef struct iterator {
void *ptr;
size_t size;
} iterator;
void it_init(iterator *t, void *ptr, size_t size) {
*t = (iterator){ ptr, size, };
}
// eq is from test(1) shell command. "eq" means "equal"
bool it_eq(iterator *t, iterator *o) {
return t->ptr == o->ptr;
}
void it_add(iterator *t, size_t n) {
t->ptr = (char*)t->ptr + t->size * n;
}
// increment the iterator
void it_inc(iterator *t) {
it_add(t, 1);
}
// return a pointer to the element
void *it_get(iterator *t) {
return t->ptr;
}
// interface
typedef int (*Fn_Sum)(void*, void*);
typedef int (Fn_Prt)(void*);
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx){
iterator end = it;
it_add(&end, n);
for(; !it_eq(&it, &end); it_inc(&it)) {
int err = fsum(sumctx, it_get(&it));
if (err) return err;
err = fprt(sumctx);
if (err) return err;
printf(", ");
}
printf("\n");
return 0;
}
// num object
struct num {
int sum;
};
void num_init(struct num *t) {
t->sum = 0;
}
void num_sum(struct num *t, int el){
t->sum += el;
}
void num_print(struct num *t){
printf("%d", t->sum);
}
void num_free(struct num *T) {
// nothing, just exists for uniform API
}
// accessors for PrintSums
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
// string object
struct str {
char *str;
};
void str_init(struct str *t) {
t->str = NULL;
}
int str_sum(struct str *t, const char *str) {
const size_t str_len = t->str == NULL ? 0 : strlen(t->str);
void *p = realloc(t->str, str_len + strlen(str) + 1);
if (p == NULL) {
free(t->str);
t->str = NULL;
return -1;
}
t->str = p;
memcpy(t->str + str_len, str, strlen(str) + 1);
return 0;
}
void str_print(struct str *t) {
if (t->str == NULL) {
printf("(nul)");
} else {
printf("%s", t->str);
}
}
void str_free(struct str *t) {
free(t->str);
}
// interface for PrintSums
int str_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct str *t = ctx;
const char **el = el0;
str_sum(t, *el);
return 0;
}
int str_PrintSums_Fn_Prt(void *ctx) {
struct str *t = ctx;
str_print(t);
return 0;
}
// and finally main
int main() {
int err = 0;
int V[] = {1,2,3,4};
iterator numit;
it_init(&numit, V, sizeof(*V));
struct num numsum; // the object that will hold the sum
num_init(&numsum);
err = PrintSums(numit, sizeof(V)/sizeof(*V), num_PrintSums_Fn_Sum, num_PrintSums_Fn_Prt, &numsum);
if (err) abort();
num_free(&numsum);
char *S[] = {"a", "d", "c", "d"};
iterator strit;
it_init(&strit, S, sizeof(*S));
struct str strsum; // the object that will hold the sum of strings
str_init(&strsum);
err = PrintSums(strit, sizeof(S)/sizeof(*S), str_PrintSums_Fn_Sum, str_PrintSums_Fn_Prt, &strsum);
if (err) abort();
str_free(&strsum); // YES! Remember to pick out the trash
}
and outputs on godbolt:
1, 3, 6, 10,
a, ad, adc, adcd,
The pointers to a constructor and destructor of "sum objects" could be passed to PrintSums too. That said one could start thinking about creating a virtual table for all these pointers (ie. one struct with function pointers that are needed for PrintSums...).
How do i safely swap a function for another function in C, as i have this
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
void *(*malloc_mem_real)(size_t);
void *(*calloc_mem_real)(void*,size_t);
void *(*realloc_mem_real)(void*,size_t);
void (*free_mem_real)(void*);
void memory__init(void) {
if (!malloc_mem_real) malloc_mem_real = dlsym(RTLD_NEXT, "malloc");
if (!calloc_mem_real) calloc_mem_real = dlsym(RTLD_NEXT, "calloc");
if (!realloc_mem_real) realloc_mem_real = dlsym(RTLD_NEXT, "realloc");
if (!free_mem_real) free_mem_real = dlsym(RTLD_NEXT, "free");
}
/*
const char *getObjectName (object *anObject) {
static char * (*func)();
if(!func)
func = dlsym(RTLD_NEXT, "getObjectName");
printf("Overridden!\n");
return(func(anObject)); // call original function
}
*/
void* _malloc(size_t sz);
int bit, saved;
void swap_malloc() {
if (bit == 0) {
void *(* malloc)() = &_malloc;
bit = 1;
write(1, "1\n", 2);
}
else if (bit == 1) {
void *(* malloc)() = &malloc_mem_real;
bit = 0;
write(1, "0\n", 2);
}
}
void* _malloc(size_t sz) {
swap_malloc(); // should swap void* _malloc(size_t sz) for void* malloc(size_t __size), bit = 0
return malloc(sz*2); // returns libc malloc(sz*2);
}
void* malloc(size_t sz) {
if (saved == 0) {
memory__init(); // save real malloc address
saved = 1;
}
swap_malloc(); // should swap void* malloc(size_t sz) for void* _malloc(size_t sz), bit = 1
return malloc(sz); // returns _malloc(sz);
}
int main() {
char * h;
h = malloc(50); // should allocate 100 instead
printf("%p\n", h);
free(h);
return 0;
}
which is meant to swap the files malloc for libc malloc but swap_malloc keeps being called recursively resulting in write: stack overflow
The basic idea is this:
calls malloc wrapper
swich malloc wrapper to libc malloc
Do functions that require libc malloc, for example printf
switch libc malloc back to malloc wrapper
There really isnt much I can say here.
Here is my lexer file:
#include <ctype.h>
#include <stdio.h>
#include "vector.h"
enum TokenType
{
tok_let = -1,
tok_iden = -2,
tok_int = -3,
tok_end = -4
};
typedef struct
{
int type;
char* str_d;
int int_d;
} Token;
char* seed;
int i=0;
char next_char()
{
i++;
return seed[i-1];
}
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
seed = in;
char tap;
if(isalpha(tap = next_char()))
{
char* iden_str="";
iden_str += tap;
char nc;
while(isalnum((nc = next_char())))
iden_str += nc;
if(iden_str == "let")
{
Token* tp;
tp->type = tok_let;
vector_push(toks, (void*)tp);
goto out;
}
Token* tp;
tp->type = tok_iden;
tp->str_d = iden_str;
vector_push(toks, (void*)tp);
}
out:
return toks;
}
int main()
{
vector* toks;
toks = get_tokens("let");
Token* ftok = (Token*)vector_get(toks, 0);
switch(ftok->type)
{
case tok_let:
printf("Its a let\n");
break;
default:
printf("Ummm lol nup\n");
break;
}
}
And here is my vector file:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct d_vector
{
void **items;
int capacity;
int total;
} vector;
void vector_new(vector *v)
{
v->capacity = 4;
v->total = 0;
v->items = malloc(sizeof(void*)*v->capacity);
}
int vector_total(vector *v)
{
return v->total;
}
static void vector_resize(vector *v, int capacity)
{
void** items = realloc(v->items, sizeof(void*) * capacity);
if(items)
{
v->items = items;
v->capacity = capacity;
}
}
void vector_push(vector *v, void* item)
{
if(v->capacity == v->total)
vector_resize(v, v->capacity * 2);
v->items[v->total++] = item;
}
void vector_set(vector *v, int index, void* item)
{
if(index >= 0 && index < v->total)
v->items[index] = item;
}
void* vector_get(vector *v, int index)
{
if(index >= 0 && index < v->total)
return v->items[index];
return NULL;
}
void vector_remove(vector *v, int index)
{
if(index < 0 || index >= v->total)
return;
v->items[index] = NULL;
for (int i = 0; i < v->total - 1; i++) {
v->items[i] = v->items[i + 1];
v->items[i + 1] = NULL;
}
v->total--;
if (v->total > 0 && v->total == v->capacity / 4)
vector_resize(v, v->capacity / 2);
}
void vector_free(vector *v)
{
free(v->items);
}
When I run the code above, I get a Seg-Fault.
How can this be happening? Here is the output of gdb:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400656 in vector_new (v=0x1) at vector.h:14
14 v->capacity = 4;
As you can see, its segfaulting when i set the vector capacity!
But why?
It segfaults because you dereference a garbage pointer:
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
The variable toks is not assigned to anything meaningful, just whatever garbage value happens to be floating about. This gets passed into vector_new() which immediately dereferences it:
void vector_new(vector *v)
{
v->capacity = 4;
Then BAM! it blows up because v points nowhere appropriate.
Try mallocing a vector before making your call to vector_new() or put the malloc in vector_new() and have it return the pointer to the new vector instead. It's also a good idea to check the return value from malloc().
You might try something like:
vector *vector_new(void)
{
vector *v;
if ( (v = malloc(sizeof(*v))) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
v->capacity = 4;
v->total = 0;
if ( (v->items = malloc(sizeof(*v->items)*v->capacity)) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
return v;
}
Then change how you call it:
vector* get_tokens(char* in)
{
vector *toks;
toks = vector_new();
And for every malloc(), let there be a free(). Don't forget to clean up this allocation too or you'll leak memory:
void vector_free(vector *v)
{
free(v->items);
free(v);
}
(You defined a vector_free(), but never called it. You might want to consider doing that too.)
invalid pointer dereference happened
vector *toks;
vector_new(toks);
Should be
vector *toks = (vector*)malloc(sizeof(vector));
vector_new(toks);
I am just working on a liberty functions in which we define our own datatypes for student and book I have to write a code which finds student by id and book by id these are the two functions. In this functions the pointers which I pass are different but the logic is the same so I got a though that why can't we write one function and pass which thing we want. I mean when we pass the student list it will return the index of student when we pass the book list it will return the book index of the book. Can we use void pointers for that??? Thank you everyone!!!
int findBookId(Book* booklist,int* bcount,unsigned int* tbid)
{
int i;
for (i=0; i<*bcount; i++)
{
if (booklist[i].id==*tbid)
{
return i;
}
}
return NOT_FOUND;
}
int findStuId(Student* stulist,int* scount,unsigned int* tsid)
{
int i;
for (i=0; i<*scount; i++)
{
if (stulist[i].id==*tsid)
{
return i;
}
}
return NOT_FOUND;
}
Assuming you have a student structure:
struct student {
int id;
char name[20];
};
You can imitate qsort() function, to design a parameter to receive a callback function and to receive the size and size of each element if you'd like use void *.
int find_ele(void *base, size_t num, size_t width,
int (*equal)(const void *, const void *),
void *param)
{
int i;
for (i = 0; i < num; ++i) {
if (equal((char *) base + i * width, param)) {
return i;
}
}
return -1;
}
Then, define a "tester":
int student_tester(const void *p1, const void *p2)
{
struct student *sp = (struct student *) p1;
int id = *(int *) p2;
return sp->id == id;
}
In main() function:
int main(void)
{
struct student student_list[] = {
0, "A",
1, "B",
2, "C"
};
int id = 2;
int index = find_ele(student_list, sizeof student_list,
sizeof(struct student), student_tester, &id);
if (index != -1) {
printf("find_ele(id=2) = student_list[%d]; name = %s. \n",
index, student_list[index].name);
} else {
printf("Not found. \n");
}
return 0;
}
This is a bit complicated. You can create macros to simplify it if you don't care.
Rename find_ele to _find_ele, and create a macro:
#define find_ele(base, num, compare, param) _find_ele(base, \
num / sizeof base[0], \
sizeof base[0], \
compare, param)
And create another macro to define a "tester":
#define define_tester(name, type, type_to_find, code) \
int name(const void *_p, const void *param) { \
type *p = (type *) _p; \
type_to_find value = *(type_to_find *) param; \
return (code); \
}
Now you can define a "tester" like this:
define_tester(student_tester, struct student, int,
p->id == value);
Complete code:
#include <stdio.h>
int _find_ele(void *base, size_t num, size_t width,
int (*equal)(const void *, const void *),
void *param)
{
int i;
for (i = 0; i < num; ++i) {
if (equal((char *) base + i * width, param)) {
return i;
}
}
return -1;
}
#define find_ele(base, num, compare, param) _find_ele(base, \
num / sizeof base[0], \
sizeof base[0], \
compare, param)
#define define_tester(name, type, type_to_find, code) \
int name(const void *_p, const void *param) { \
type *p = (type *) _p; \
type_to_find value = *(type_to_find *) param; \
return (code); \
}
struct student {
int id;
char name[20];
};
define_tester(student_tester, struct student, int,
p->id == value);
int main(void)
{
struct student student_list[] = {
0, "A",
1, "B",
2, "C"
};
int id = 2;
int index = find_ele(student_list, sizeof student_list, student_tester, &id);
if (index != -1) {
printf("find_ele(id=2) = student_list[%d]; name = %s. \n",
index, student_list[index].name);
} else {
printf("Not found. \n");
}
return 0;
}
Yes you can use void*, but while dereferencing you should know the exact type of the pointer.
So, when you can your function, add another parameter:
type = 0 for Books
= 1 for students
And then your function becomes:
int findId(void* list,int* count,unsigned int* tbid, int type)
{
Book* booklist=NULL;
Student* stulist=NULL;
int i;
if(type===0)
booklist = (Book*) list;
else if(type==1)
stulist = (Student*) list;
else
// Handle this undefined case
// And now use the same type variable to decide which pointer to use to match the values
. . . .
}
Yes you can use void pointer, if you are trying to store address of your array..Your array may contain integer types or some other datatypes stored, it doesn't matter, but right typecasting while de-referencing the void pointer is important.
I don't think you can use void* in these functions.
If you changed your functions to one and created something like:
int findObjId(void* objlist,int* count, unsigned int* objid)
{
int i;
for (i=0; i<*scount; i++)
{
if (objlist[i].id==*objid)
{
return i;
}
}
return NOT_FOUND;
}
you won't be able to extract the data from objlist. Neither *objlist, nor objlist[i] can be dereferenced to evaluate to an object. The compiler will definitely stop you from using any such statement.
If you have the option, switch to C++. Using templates, you can accomplish your goal without breaking a sweat.
file stack.h
typedef struct
{
void *elems;
int elem_size;
int log_len;
int alloc_len;
void (*free_fn)(void *);
} stack;
void stack_new(stack *s, int elem_size, void (*free_fn)(void *));
void stack_dispose(stack *s);
void stack_push(stack *s, void *value);
void stack_pop(stack *s, void *address);
and the implementation file stack.c
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define assert(condition) if(!condition) printf("assert fail\n");exit(0)
void strfree(void *elem);
int main()
{
stack s;
int i;
char *copy, *top;
const char *friends[] = {"joe", "castiel", "lily"};
stack_new(&s, sizeof(char *), strfree);
for(i=0; i<3; i++)
{
copy = strdup(friends[i]);
stack_push(&s, &cp);
}
for(i=0; i<=3; i++)
{
stack_pop(&s, &top);
printf("%s\n", top);
}
stack_dispose(&s);
return 1;
}
void strfree(void *elem)
{
free(*(char **)elem);
}
void stack_new(stack *s, int elem_size, void (*free_fn)(void *))
{
assert(elem_size > 0);
s->alloc_len = 4;
s->free_fn = free_fn;
s->log_len = 0;
s->elem_size = elem_size;
s->elems = malloc(s->alloc_len * s->elem_size);
assert(s->elems != NULL);
}
void stack_dispose(stack *s)
{
int i;
if(s->free_fn)
{
for(i=0; i<s->log_len; i++)
{
s->free_fn((char *)s->elems + i * s->elem_size);
}
}
free(s->elems);
}
void stack_push(stack *s, void *v)
{
if(s->log_len == s->alloc_len)
{
s->alloc_len *= 2;
s->elems = realloc(s->elems, s->alloc_len*s->elem_size);
assert(s->elems != NULL);
}
memcpy((char *)s->elems+s->log_len*s->elem_size, v, s->elem_size);
s->log_len++;
}
void stack_pop(stack *s, void *address)
{
assert(s->log_len > 0);
void *source = (char *)s->elems + (s->log_len - 1) * s->elem_size;
memcpy(address, source, s->elem_size);
s->log_len--;
}
So it compiles but it doesn't run.
It has a warning about comparison between pointer and integer which comes from the code
assert(s->elems != NULL);
It is broken somewhere, it will not print out the three names defined here
const char *friends[] = {"joe", "castiel", "lily"};
I know the code is bit of too much, but I really wish to get some help, I'm at my wits end here.
One problem is your assert macro:
#define assert(condition) if(!condition) printf("assert fail\n");exit(0)
The exit(0); is executed regardless of whether the condition is true or false (look at the generated code again). If you want assertions, use the standard #include <assert.h>.
Your first identified problem is with:
assert(s->elems != NULL);
Given the definition, this is equivalent to:
if (!s->elems != NULL)
printf("assert fail\n");
exit(0);
The !s->elems is an integer, either 0 or 1, compared with a null pointer constant. Hence the warning. When writing macros, enclose arguments in parentheses. At minimum:
#define assert(condition) if(!(condition)){printf("assert fail\n");exit(1);}
This still isn't a good macro, but at least it will get rid of the first compilation error, and your stack_new() won't exit when it is called just because it is called. Note that it is conventional to exit with a non-zero status when there is a problem — exiting with zero indicates success.
Run your code in a debugger using GDB to see what it is doing line by line. Google "gdb cheat sheet" to get started and compile your code with -g.