Best and safest API for a function which fills a buffer with variable-length data

api-designc

I have a function which receives a buffer and returns some data in the buffer. The data can be smaller than the buffer capacity.

Which is the best and safest API for this?

  • int fn(void *buffer, size_t buffer_len): the size of the data written to buffer is returned by the function. Downside: the return value must also have a way to indicate that some error occurred (in-band error indicator).
  • errno_t fn(void *buffer, size_t *buffer_len): in this case, buffer_len works both as input (the buffer capacity) and output (the data size). The function can return an error code. I think this is OK, but somewhat awkward.
  • errno_t fn(void *buffer, size_t *data_len, size_t buffer_len): like the previous, but with input/output separated in two arguments. Also returns error code, but is also awkward due to too many arguments.

(Any other options?)

Best Answer

I think the best API for such case is to create a buffer specification and deal with it, like:

struct sbuf {
  void *data;
  size_t size, pos, length;
};

// void if malloc() errors do abort(). int otherwise, to report error
void sbuf_alloc(sbuf *sb, size_t minsize);
void sbuf_free(sbuf *sb);

int /* or errno_t, whatever */ fn(sbuf *sb);  

With such API, you'll avoid 1) long and cumbersome argument lists, 2) chance to mistake length for size and vice versa, and will gain instead understanding of object-like gist of your buffers.