Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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

share|improve this question
1  
Which option best fulfills your software's requirements? –  Robert Harvey Apr 17 at 23:14
    
This whole thread is probably going to be nothing more than a big collection of opinions where no one is definitively better than the other, but I'll throw my two cents in. Don't forget exception handling as a (perhaps appropriate) alternative. –  Joe Rounceville Apr 18 at 18:16
add comment

3 Answers 3

I'd support david's point of maintaining consistency, and since this seems to be C (and not C++), the required functionality is very much like the POSIX file read:
input buffer instead of a file.
output buffer for user, remains same.
number of bytes read or length, remains same.

So, I think sticking to POSIX is a good thing, and so the first option would be better, with a return of -1 for error (negative values for multiple errors is possible but appears clumsy):
int fn(void *buffer, size_t buffer_len)

share|improve this answer
add comment

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.

share|improve this answer
add comment

A question we have pondered frequently.

  1. Look at how similar situations are handled elsewhere in your API. Consistency is a very high priority and if there are established principles, stick to them.
  2. The language matters. It is hard/impossible to return values in parameters in some languages (Java).
  3. Consider using a struct or collection instead of a raw pointer. The byte array in Java carries its length with it.
  4. I/O parameters are horrible to code with. Avoid them!
  5. A return value should not be both a success indicator and a length, but if you break any rules this one is the least serious.

Overall my preference in C/C++ generally is to return bool success/failure, and provide a secondary function (GetLastError()) to get the real error code.

In the case of Read (only) my preference is to return the length read as return value of function, with a special value for error (-1). Not the nicest, but convenient.

If the data you are reading is known to be Ascii, then return a null-terminated string to give the length, and bool true/false for the function return.

[Regrettably this is all a matter of opinion, which makes this a question at risk of being closed.]

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.