Warning for anonymous union assignment in C

Viewed 135

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?)

1 Answers

One way to get around the error is to use designated initialization:

return (result){.error=no_error, .value=popped_value};
Related