I'm building a small demonstration of a stack in C. As C has no exceptions, I'm trying out the result pattern (similar to Result<> in Swift 5) to deal with errors in creation, push, and pop.
I've created a header file that includes an error enum:
typedef enum {
no_error,
illegal_stack_capacity,
out_of_memory,
stack_element_too_large,
stack_full,
stack_empty
} stack_error;
a struct for the stack itself (I am using a stack of strings for concreteness, because at this point I am simply experimenting:
typedef struct {
char** data; // array of strings, capacity set on create()
int capacity; // have to store this separately!
int top; // index of next slot to fill, also the size
} stack;
and now to capture errors, I thought I would build a little struct that has an error part and a success part. As I am experimenting, I tried to have the error part do double duty as both a discriminated union tag as well as capture the error. This may be a hack, but it leads to (what I think is maybe) an interesting question.
typedef struct {
stack_error error;
union {
stack* stack; // because create() returns a stack
char* value; // because pop() returns a string
};
} result;
For reference (and sorry for the clutter), I have these functions:
result create(int capacity);
int size(const stack* s);
bool is_empty(const stack* s);
bool is_full(const stack* s);
stack_error push(stack* s, char* item);
result pop(stack* s);
void destroy(stack** s);
Now the question is that every time I build a result object, the C compiler seems to always assume the anonymous union component of my result struct is supposed to be a stack*. When I write, in my create function
return (result){no_error, s};
the compiler is fine with it, but when I write this in my pop function:
return (result){no_error, popped_value};
the compiler gives me a warning:
boundedstack.c:57:31: warning: incompatible pointer types initializing
'stack *' with an expression of type 'char *'
[-Wincompatible-pointer-types]
return (result){no_error, popped_value};
^~~~~~~~~~~~
I know I can get around this by (1) making the union not be anonymous or (2) creating separate types for stack_result (for create) and string_result (for pop), and maybe I should do that, but I am intrigued by this warning was wondering if any C language experts would know if anything in the language dictates that kind of warning, or if the warning was simply a decision by the compiler implementers to say "hey well I am just going to assume the proper type for the union is the first one I see". The code works just fine, but it seems to me the compiler could have done a better job. Or could it have? Could the compiler have done a better job? Or would it be too expensive of a check in the compiler?
(I really don't want to suppress warnings, as that is bad practice. Am I wrong to have tried the anonymous union?)
One way to get around the error is to use designated initialization:
return (result){.error=no_error, .value=popped_value};
Related
Suppose we have a function pointer on a struct, which has the struct itself as the first argument, a typical callback scenario.
typedef void (*callback_type)(my_struct_type *mst, int whatever);
typedef struct {
// lots of fun stuff
callback_type notify_me;
} my_struct_type;
This produces a compiler error on the first typedef, as one might expect. error: unknown type name my_struct_type. Reversing the definitions produces the same result, but the unknown type is callback_type.
The easy solution is to do the following:
typedef struct my_struct_type_S {
// lots of fun stuff
void (*notify_me)(my_struct_type_S *mst, int whatever);
} my_struct_type;
However, doing this elides the function pointer type definition, which it would be nice to be able to easily refer to later, and use for static type checks, nice error messages, etc.
Any suggestions on how to resolve this?
Edit on "possible duplicate":
This scenario involves function pointer typedefs that are arcane to many people. I think this is a good example for that case, and additionally, the accepted answer is very clean, clear, and simple.
You can do this by giving the struct a tag and using a forward declaration of the struct. Then you can use the typedef for the function pointer, and subsequently complete the definition of the struct.
typedef struct my_struct_type_S my_struct_type;
typedef void (*callback_type)(my_struct_type *mst, int whatever);
struct my_struct_type_S {
// lots of fun stuff
callback_type notify_me;
};
You need to define the tag of the struct
typedef void (*callback_type)(struct _my_struct_type *mst, int whatever);
typedef struct _my_struct_type {
// lots of fun stuff
callback_type notify_me;
} my_struct_type;
I write a code with a connectivity list of a flexible type.
My database contains a list of nodes with data that might be a char* or a VERTEX* (struct defined by me). hence I defined the struct as with a field void*.
I also wish to have an operation which compares the strings in that field, so the list has a field defined:
DATA_EQ DataEqual
and defined a function which checks if the data of two nodes is equal:
typedef BOOL (*DATA_EQ) (void* pl, void* pr);
in order to define a DATA_EQ function for the list, in the case of string data, I created the following function in the .c file:
static BOOL stringDataEqual(char* pd1, char* pd2){
return ( strcmp(pd1, pd2) == 0 );
}
Finally, I want this function to be defined on my list, so I wrote:
pList->dataEqual = stringDataEqual;
but I guess the fact that I tried to specify the void* as char* is not good.
I haven't worked with pointers to functions in the past, so I might have done some silly mistakes...
I got the warning (after running gcc to complie):
warning: passing argument 1 of ‘ListCreate’ from incompatible pointer type [enabled by default]
I need my code to compile without any warnings, how do I solve/work around that?
Thanks ahead to anyone who helps,
Oded
Use casts to cast to and from void pointers. Your function becomes:
static BOOL stringDataEqual(void* pd1, void* pd2) {
return ( strcmp((char*)pd1, (char*)pd2) == 0 );
}
You can call this function by casting the parameters to void*.
I'm relatively new to C and trying to understand structs and pointers. What does the *Building at the end of this struct declaration do?
typedef struct building {
char *floor;
struct building *nextBuilding;
} *Building;
Does it mean that from now on when I do
Building someBuilding = malloc(sizeof(struct building));
somebuilding is a pointer to a building?
Yes, when you write:
typedef struct building { … } *Building;
Building bp;
then bp is a pointer to a struct building. However, it is frequently regarded as bad style to include the pointer in the typedef; code is easier to understand if you use:
typedef struct building { … } Building;
Building *bp;
Now it is clear looking at the definition of bp that the type is a pointer. If you are never going to access the internals of the structure, then it doesn't matter too much (but look at FILE * in <stdio.h>; you always write FILE *fp, etc). If you're going to access the internals:
printf("Floor: %s\n", bp->floor);
then it is better to have the pointer visible. People will be mildly surprised to see Building bp; and then later bp->floor instead of bp.floor.
To answer the question: yes. You now have a type Building that is a pointer to a struct building and you can do this:
Building someBuilding = malloc(sizeof(struct building));
someBuilding->floor = malloc (sizeof(char)*20);
strcpy(someBuilding->floor, "First floor");
someBuilding->nextBuilding = NULL;
etc.
note that this might not be a good idea in all cases. For example if you declare a method:
void setFloorName(Building building, char* name)
you can't really tell that you need to pass a pointer to a building struct, but if you do:
void setFloorName(Building* building, char* name)
you immediately see that the function takes a pointer.
In the following code, "stk" is treated as if it is a pointer. But after looking at it from every angle for hours, I cannot for the life of me see how it is a pointer. Can someone please explain what I'm missing?
struct T {
int count;
struct elem {
void *x;
struct elem *link;
} *head;
};
T Stack_new(void) {
T stk;
NEW(stk);
stk->count = 0;
stk->head = NULL;
return stk;
}
My interpretation says that T is a struct, and therefore stk is a local, automatic variable containing a struct. It is not a pointer, but then it gets treated as a pointer, leaving me stuck in a WTF state.
More Background
This code is from a book called "C Interfaces and Implementations" by Hanson. He creates a library of abstract data types that expose an interface and hide the implementation. The stack is the first one he covers. I'm a long-time programmer just now digging into C, and apparently there's some way of parsing this syntax that I'm missing. Thanks.
In case it is relevant, here is the definition for NEW and the things that new calls:
#define NEW(p) ((p) = ALLOC((long)sizeof *(p)))
#define ALLOC(nbytes) \
Mem_alloc((nbytes), __FILE__, __LINE__)
extern void *Mem_alloc (long nbytes,
const char *file, int line);
In the snippet above, T stk will declare stk as a variable of type T. However type T isn't defined anywhere, and the code won't compile.
If it instead said struct T stk;, it would be declaring stk as a variable having type struct T. However, the attempts to dereference stk would be meaningless and the code would again fail to compile.
To make the example work, you could add something like,
typedef struct T *T
which defines type T to be a pointer to struct T. I would find this highly confusing though.
I would like to know if it is possible to get the type to which I would like to cast dynamically. For eg.
void *ptr;
typedef struct {
..
common_field;
..
} some;
typedef struct {
..
common_field;
..
} some_other;
Now I want to know if I can typecast ptr to type some or some_other dynamically.
precisely what I want to know is if it is possible to have a macro, TYPE_CAST(comdition) which gives me the type like shown below:
(TYPE_CAST(condition)) ptr->common_field
should be equivalent to
((some *) ptr)->common_field or ((some_other *) ptr)->common_field
based on the condition
The following doesn't work, just giving this so that it might be clear to understand c than english:
TYPE_CAST(condition) ((condition) ? (some *) : (some_other *))
Can something along these lines can be done.
Thanks.
That's pretty much not possible. The type of an expression is determined at compile time; it can't depend on any execution time condition.
You can, given a void* that you know points to an object of one type or the other, do something similar (I have not tested this):
condition ? ((some*)ptr)->common_field : ((some_other*)ptr)->common_field
Note that the ->common_field part of the expression has to be repeated; the compiler has to know the type of the left operand of the -> operator.
(Depending on the context, an if/else statement might be clearer.)
A way to design your data structures to avoid your problem could be:
typedef struct {
int common_field;
union {
struct {
int member1;
} some;
struct {
char* member2;
} some_other;
};
} common_struct;
common_struct* ptr;
Then you can easily access the common member with ptr->common_field regardless of which of the two variants you have. I would imagine that the value of this common field will tell you which of the two members of the union you need to use to access the remaining members, which you will then access as ptr->some.member1 or ptr->some_other.member2.
C90 does not support this directly
I assume you want to write a generic list of some sort in c90. Here are some snippets i use in a generic c90 list of mine:
typedef struct {
void *rigth;
void *left;
void *value;
int index;
}GENLIST_node;
#define GENLIST_getValuePtr(NODE, index, valptr) __GENLIST_getValuePtr ((NODE), (index), (void*)(valptr))
using this you can access the content when calling it and always get the rigth type back. Here are some examples:
int *NODEVALA = NULL;
double *NODEVALB = NULL;
char *NODEVALC = NULL;
GENLIST_getValuePtr(&AnyNode, -1, &NODEVALA);
GENLIST_getValuePtr(&AnyNode, -1, &NODEVALB);
GENLIST_getValuePtr(&AnyNode, -1, &NODEVALC);
there are obviousely some parts missing , but what i want to point out is that NODEVALA, NODEVALB and NODEVALC have whatever type you want them to have and the list saves them in form of a void pointer.
in your case this could be done with recursive calls during runtime
switch(condition){
case condition_structA:
structA *X;
getValPtr(&X);
...
break;
structB *X;
getValPtr(&X);
...
case condition_structB:
break;
}
In C90 there is no way the compiler can be used to do things like that automatically. To do this you would need polymorphism and that would be C++ or better.