So I a function which returns a pointer to a struct (parse_files_result_t*
). This struct contains a union:
struct parse_files_result_t{
result_tag tag;
union {
struct parse_file_error_t *err_ptr;
struct parse_file_response_t *ok_ptr;
} data;
};
And I wanted to use the union to return an *err_ptr
or an *ok_ptr
based on the calculations in the function.
So I wrote the following code:
parse_files_result_t* result = (parse_files_result_t*)malloc(sizeof (parse_files_result_t));
if (success) {
parse_file_response_t response = //data
*result = parse_file_result_t{result_tag::Ok, result->data.ok_ptr = &response};
return result;
} else {
parse_file_error_t errorresponse = //data
*result = parse_files_result_t{{result_tag::Err}, {result->data.err_ptr = &errorresponse}};
return result;
}
So far so good. The else
part, where a parse_file_error_t
gets returned, works fine because the parse_file_error_t
is the first part of the union. In the if
part, I want to return only the parse_file_response_t
. Because this is the second "part" of the union, I get this error:
error: cannot convert ‘parse_file_response_t*’ to ‘parse_file_error_t*’ in initialization
Even though I wrote result->data.ok_ptr
, my compiler tries to put the parse_file_response_t response
into the parse_file_error_t
part of the union.
How can I fix this?
Thanks for your help!
Even though I wrote
result->data.ok_ptr
, my compiler tries to put theparse_file_response_t response
into theparse_file_error_t
part of the union.
Well, yes. You compacted so much into a single line, you lost track of what you are telling the computer to do.
*result = parse_files_result_t{result_tag::Ok, result->data.ok_ptr = &response};
This statement does several things. (Work from the inside out to follow along. We'll start from result->data.ok_ptr = &response
and work out to *result = [stuff]
.)
response
to result->data.ok_ptr
.parse_files_result_t
object is constructed using the initial values result_tag::Ok
and the value that was assigned in step 1. These values are assigned to the tag
and data.err_ptr
members, hence the error.*result
, overwriting the assignment that was done in step 1.Simplify your code to (almost) get what you want.
result->tag = result_tag::Ok;
result->data.ok_ptr = &response;
This gives more lines of code, but the syntax is clearer. Also, you are creating less work for the computer since this no longer tries to create a temporary parse_files_result_t
object.
There is still a problem, though, in that result->data.ok_ptr
will be a dangling pointer. Unfortunately, I think addressing that (and addressing the other issues) goes outside the scope of your question.