0

In Go they often do the whole (err, val) thing, in Rust they do similar (+ syntactic sugar).

I'm not sure if I should have this type of struct for each of my types:

typedef struct {
    int status;
    char *const *c_str_arr;
    size_t size;
} StatusAndArrayCStrArray;

extern void cleanup_struct_cstr_array(StatusAndArrayCStrArray *status_and_array) {
    if (status_and_array->c_str_arr != NULL) {
        free((void *) status_and_array->c_str_arr);
        status_and_array->size = 0;
    }
}

static const StatusAndArrayCStrArray statusAndArrayCStrArrayNull = {
    EXIT_FAILURE, NULL, 0
};

That seems to be a lot of wasted space. Maybe a union would be better? - I've also seen some perror stuff so maybe I'm meant to set an error code and return the value, and then first check if there is an error the perror-way else return the value?

Related: Error handling in C code

A T
  • 13,008
  • 21
  • 97
  • 158
  • So I'm planning a few thousand functions each returning either the value or an error, from remote server. The value is either a scalar, an array of some description (with a separate field for size), or a full on `struct` representing the remote entity. – A T May 16 '21 at 09:24
  • Irrelevant but for what it is worth there's no need to cast `free`'s argument or return value to `void *` (same goes for `malloc`/`calloc`/`realloc`). – Harry K. May 16 '21 at 10:15

1 Answers1

0
  1. As I understand c_str_arr keeps the error message. It does not have to be a part of this structure. It does not have to reside in the RAM (if RAM is a concern - for example uC programming). Have a second array with error messages in .rodata.

  2. size probably it is the length of the message string. If message string is the null character terminated C string you do not need at all. I do not see any need of the dynamic allocations here.

  3. Eventually you need only the status code, nothing else.

  4. extern void cleanup_struct_cstr_array functions are extern by definition and you do not need the extern keyword

EDIT (OPs comment):

So I'm planning a few thousand functions each returning either the value or an error, from remote server.

If the server will return the complete message with some payload you cant use pointers to that data, you need to embed the data into the message.

typedef struct {
    int status;
    size_t payload_size;
    char   payload[];
} StatusAndArrayCStrArray;

payload will be the data returned from the server. It can be error message or another data. It can also be nothing.

Eventually if both size know the size of the payload (as it is defined somehow depending on the status) you may not need the payload_size member at all.

0___________
  • 60,014
  • 4
  • 34
  • 74
  • I was more thinking `c_str_arr` is for when the return value is a c_str_arr and not an error, else return just the error code. I renamed `int error` to `int status` and have been using `status = EXIT_SUCCESS` and checking for that. But it all seems rather unwieldy… – A T May 16 '21 at 09:32
  • So basically if all my functions return `StatusAndArrayCStrArray` then it's not a bad design as I thought? – A T May 16 '21 at 10:12