How do I return an error code in C when the return type of the function doesn't allow me to do that?

Viewed 190

I know that the title is not self explicative, but I couldn't express in a few words. Anyway, the problem is that I have a C function that returns a struct consisting of 3 integers. Here it is its definition.

typedef struct {
  uint8_t r;
  uint8_t g;
  uint8_t b;
} Color;

and here it is the function

Color PPMImage_getPixel(PPMImage *ppmImage, uint32_t x, uint32_t y) {
  // FIXME: Check if (x, y) is in bounds.

  return ppmImage->data[y * ppmImage->width + x];
}

Now when a specific condition fails I want to return an error value that tells the caller that the function encountered an error, but I can't since the return value is a struct with 3 unsigned integers and I can't, for example, set each field to -1 or return NULL because I'm not returning a pointer. Is there an elegant and efficient way to do that?

3 Answers

Change the type of the return value to be the err code of the function and pass a pointer of the struct color to be returned

ie:

int PPMImage_getPixel(PPMImage *ppmImage, uint32_t x, uint32_t y, Color * color)
{
 // FIXME: Check if (x, y) is in bounds.
 // TODO: validate color isn't null and valid, otherwise return -1

 (*color) = ppmImage->data[y * ppmImage->width + x];
  return 0;
}

I would rather have a pointer to a buffer as input parameter to the function and return a int.

int PPMImage_getPixel(Color* p_color, PPMImage *ppmImage, 
                      uint32_t x, uint32_t y) 
{
    if (some error)
    {
        return 0;
    }
    
    // Copy the struct into buffer
    memcpy(p_color, &ppmImage->data[y * ppmImage->width + x], sizeof (Color));

    return 1;
}

Assuming some struct that you did not define, but you can change that. Created this in order to have something which can compile.

typedef struct PPMImage
{
    uint8_t width;
    Color data[10];
} PPMImage;

Create buffer in main() and have the address of that buffer as input.

int main(void)
{   
    PPMImage image;

    Color color_buf;
    uint32_t x = 5, y = 3;

    if (!PPMImage_getPixel(&color_buf, &image, x, y))
    {
        printf("ERROR PPMImage_getPixel()\n");
        exit(0);
    }

    printf("PPMImage_getPixel() returned no error.\n");

    return 0;
}

One approach is to assign the result to an output parameter and return the error code, like this:

int PPMImage_getPixel(PPMImage *ppmImage, uint32_t x, uint32_t y, Color *result);

However, since I'm a fan of the command-query separation I would assign the error code to an output parameter as well:

void PPMImage_getPixel(PPMImage *ppmImage, uint32_t x, uint32_t y, Color *result, int *error);

Another approach is to define the error out of existence by returning the nearest pixel if x or y is too large:

Color PPMImage_getPixel(PPMImage *ppmImage, uint32_t x, uint32_t)
{
    if (x < 0) {
        x = 0;
    } else if (x > xMax) {
        x = xMax;
    }
    if (y < 0) {
        y = 0;
    } else if (y > yMax) {
        y = yMax;
    }
    ...
}
Related