I'm pretty new to C so I decided to implement SRFI-1 (linked-list library) to help me learn.

What I have so far is working, but only handles integers.

typedef struct pair {
  int car;
  struct pair *cdr;
} pair;

From what I've read I can use a void * for the car:

typedef struct pair {
  void *car;
  struct pair *cdr;
} pair;

This works but I get lots of these...

llist.c:262:3: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘void *’
llist.c:27:7: note: expected ‘void *’ but argument is of type ‘int’

I've found some workarounds but before diving in and fixing everything I want to be sure this is the appropriate way to go.

The only other way I can think of is using some sort of generic object type:

typedef struct object {
  union {
    int fixnum;
    double flonum;
  }
}

typedef struct pair {
  object *car;
  struct pair *cdr;
} pair;

Or something similar.

Is there a best practice for generic functions/data types?

The full source is here.

share|improve this question
This depends on what your goal is. Do you want to produce a linked list library that will be useful to users in C? Or do you want to produce something in the spirit of the SRFI-1? A straightforward copy of that won't produce idiomatic C code. – Winston Ewert May 23 '11 at 2:46
@Winston Ewert: I'd like to make this idiomatic C even if that means deviating from SRFI-1. The purpose of doing this is to help me learn C (pointers, memory management, etc), so a straightforward port isn't really what I'm going for. – Jack Trades May 23 '11 at 4:20
This is not so much a review of working code as a request to help solve a problem. Probably a better fit on Stack Overflow. – Adam Davis May 23 '11 at 12:44
@Adam Davis, its really a question about best practices. However, that's still off-topic for this site. – Winston Ewert May 23 '11 at 16:50
1  
@Jack Trades, there are a number of best practice questions here which haven't been challenged. But the official policy is no best practice questions. – Winston Ewert May 23 '11 at 21:53
show 1 more comment

1 Answer

up vote 1 down vote accepted

void* is the standard to implement such generics in C. The trouble with union is that the end-user cannot put their own types/structs in it. With void * a pointer to a user-defined struct can be used. However, be careful about memory leaks!

The warnings you are getting is because you haven't consistently used void*.

llist.c:262:3: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘void *’

This indicates that you are printf'ing the data as if it were an int. But you don't what it is so you can't do that. Either don't provide printing options or provide a way to control how the object prints.

llist.c:27:7: note: expected ‘void *’ but argument is of type ‘int’

You have a void * and you are passing it to a function that takes int. Everything inside your library should be using void * not int. Only the actual code using your library should conver the void * into int or whatever they are using.

share|improve this answer
So I should implement everything with void* and let the user worry about the rest, which would look something like this? int j = 42; void *p = &j; vpair *k = vcons(p, NULL); printf("\n%d\n", *(int *)k->car); Presumably I/the user would create some type of wrapper functions which would hide most of the pointer stuff? I definitely have one foot over the edge of the limit of my knowledge here, so I'm sorry if I'm not making sense. – Jack Trades May 23 '11 at 20:41
@Jack Trades, firstly, j appears to be a local variable. You really shouldn't take pointers from local variables because they will become invalid as soon as the function ends. You really need to malloc space for an int, and use that. But then you need to free the memory when its not being used anymore. – Winston Ewert May 23 '11 at 21:50
@Jack Trades, I'm not seeing any sort of wrapping which would improve situation. You could write wrappers for specific versions of the list. I.e. you could write an int linked-list which used the original linked list underneath. However, I don't think it would be very useful. – Winston Ewert May 23 '11 at 21:52
@Winston Ewert: Yes j was a local var and I can see now why that won't work, thank you. So code like printf("%d", *(int *)k->car) is what is expected from generic libraries like this? I was originally thinking of writing wrappers like an int linked-list, but after reading your comments and considering a list of heterogeneous types I realize that would be mostly pointless. My idea of a generic print_list function seems to be drifting further and further away. – Jack Trades May 24 '11 at 4:11
@Jack Trades, generic libraries like this aren't common in C because there isn't a good way of doing it. The ones I have seen do it that way. – Winston Ewert May 24 '11 at 14:22
show 4 more comments

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.