Search code examples
cuint8t

returning a pointer to an array of uint8_t from a C function - get compiler errors


I have a function:

uint8_t*  createTestBuffer()
{

    uint8_t buffer[] = {5,7,3,4,1,9,3};
    return &buffer;
}

runing it:

uint8_t *buff = createTestBuffer();

returns compiler errors:

c_programming.c:11:9: warning: incompatible pointer types returning 'uint8_t (*)[7]' from a function with result type
      'uint8_t *' (aka 'unsigned char *') [-Wincompatible-pointer-types]
        return &buffer;

Im returning a pointer to an array of uint8_t from my function. So what am I getting wrong here?


Solution

  • The compiler told you that return &buffer; is returning a pointer to an array of 7 uint8_t (spelled uint8_t (*)[7]), but you said the function returns uint8_t *, and these are different and incompatible pointer types.

    If you wrote return buffer;, the types would be correct but the code would still be wrong. You can't safely return a pointer to a local array that's on the stack.

    Either make it static const uint8_t buffer[] = { … }; and change the function return type to const uint8_t *, and use accordingly (which is thread-safe because the data never changes):

    const uint8_t *createTestBuffer(void)
    {
        static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
        return buffer;
    }
    

    Or use dynamic allocation in some form as:

    uint8_t *createTestBuffer(void)
    {
        static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
        uint8_t *rv = malloc(sizeof(buffer));
        if (rv != 0)
            memmove(rv, buffer, sizeof(buffer));
        return rv;
    }
    

    Note that the calling code here needs to check that it gets a non-null pointer back again, and it must also ensure it calls free() on the returned pointer unless it is null (when calling free() becomes optional).

    Or make the caller pass the buffer – living dangerously by assuming that the user knows to pass enough space:

    void createTestBuffer(uint8_t *output)
    {
        static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
        memmove(output, buffer, sizeof(buffer));
    }
    

    Or living less dangerously:

    static inline size_t min(size_t a, size_t b) { return (a < b) ? a : b; }
    
    void createTestBuffer(uint8_t *output, size_t outlen)
    {
        static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
        memmove(output, buffer, min(sizeof(buffer), outlen));
    }
    

    There are other ways to handle 'output buffer smaller than copied buffer'; this code copied as much as was safe, but you could return a 0 or 1 status indicating truncation, or assert that the supplied length is not smaller than the required length, or …