Home > Enterprise >  How would you return error codes in an embedded system? [closed]
How would you return error codes in an embedded system? [closed]

Time:10-06

So I'm programming my own HAL and now I'm in a little dispute with myself about how to return error codes from functions. So the general idea is that I have an I2C_read() function:

int32_t I2C_read(I2C_handle_t i2c, uint8_t addr, uint8_t reg);

which returns the byte on success, or a negative error value when an error occurs. Since I only read one byte here from I2C the int32_t will have enough space to handle both, error code on error and read byte on success. But now I've read that it is general bad practice to return two different "types" of data from a function. So my dispute is now how I should do this: Either I do:

i2c_err_t I2C_read(I2C_handle_t i2c, uint8_t addr, uint8_t reg, uint8_t *data);

where I just put in data as a buffer for the read byte and return the error code
or

uint8_t I2C_read(I2C_handle_t i2c, uint8_t addr, uint8_t reg, i2c_err_t *err);

where I return the data and put in a buffer for the error.

So which one would you guys say is better or maybe you can give me another idea how I could implement this.

I also thought about creating a struct where I put in the returned value and the error code, but I thing that would be too overengineered 'cause of the handling of arrays with this kind of approach.

CodePudding user response:

But now I've read that it is general bad practice to return two different "types" of data from a function.

Indeed, it is often better to split data and error handling, so there's no accidental mix-ups. This also enables more advanced error handling (more error causes than one).

i2c_err_t I2C_read(I2C_handle_t i2c, uint8_t addr, uint8_t reg, uint8_t *data);

This version is how most professional APIs are designed - with the return type (enum, struct etc) reserved for the result variable. Commonly, every single public function in that library would use this same return type, but document which error codes it returns under which conditions.

Technically, it's not wrong to pass the error code through a parameter either, but using the return type is "de facto standard" and how most libraries do it.

Also, it means you can write code like: if(I2C_read(...) == SOMETHING), in case the caller is only interested in checking one specific result code.

It's also common practice to have the caller pass these errors along to some project-wide error handler, which prints/logs/takes action etc.

  • Related