Domanda

say I have two 'modules'. For instance the hardware-interface layer of a RS-232 port and a layer above it to make it more abstract.

I have a receive buffer like this: U8BIT myBuffer[MAX]. U8BIT is typedeffed: typedef unsigned char

There are however two type of messages that can be received. One that has a header and another one that doesn't have a header. The logic for this is already written.

The 'layer above' will access this buffer but it should have no knowledge whether this is a header or header-less message.

Thus I have a function like this:

U8BIT * fooBuffer(U8BIT * maxLength)
{
    U8BIT * retval;
    if( isHeaderless() )
    {
        retval = &(myBuffer[0]);
        *maxLength = MAX;
    }
    else
    {
        retval = &(myBuffer[5]);
        *maxLength = MAX - 5;
    }
    return retval;
}

How can I make sure that any function calling this function is not able to alter the contents of the returned pointer?

Yes I know it will always be possible. And not trying to make it harder for others to do try to modify it. I want it to be 'not possible' so that it will be less easier to make mistakes because the compiler will complain if you do try to modify a const.

Can I just declare the function as follows: const U8BIT * fooBuffer(U8BIT * maxLength)

È stato utile?

Soluzione

Use const U8BIT * as the return type of the function.

For example in your function:

const U8BIT * fooBuffer(U8BIT * maxLength)
{
    U8BIT * retval;  

    // code

    return (const U8BIT *) retval;
} 

If retvalpointer is not dereferenced inside your fooBuffer function, declare it also as const U8BIT * and then the cast in the return statement is no longer needed.

Altri suggerimenti

How can I make sure that any function calling this function is not able to alter the contents of the returned pointer?

Return a pointer to const that will indicate your intent to users of your code.
However, note there is no guarantee that they wont be able to modify it. Remember that they can, and if they do it will be an Undefined Behavior.

You can only follow the correct semantics and hope someone will not abuse pointer hackery to break your code. It is always possible to break a code as long as one has access to the code.So all you can do is express your intent clearly.

My own rule of thumb is: whenever I feel the urge to return a pointer from a function, I regard it as a big red flag stating that my program design is bad. Though returning const pointers is perhaps a rare exception to that rule.

In your case, the code would probably benefit from a re-design. Here is my proposal.

#define FIRST_INDEX       0u
#define SOME_OTHER_INDEX  5u
#define N                 SOMETHING

static const uint8_t MAX = something;
static uint8_t myBuffer [N];


uint8_t fooBuffer (const uint8_t* retVal)
{
    uint8_t maxLength;

    if( isHeaderless() )
    {
        retval = &myBuffer[FIRST_INDEX];
        maxLength = MAX;
    }
    else
    {
        retval = &myBuffer[SOME_OTHER_INDEX];
        maxLength = (uint8_t) (MAX - SOME_OTHER_INDEX);
    }

    return maxLength;
}

Program design changes:

  • Ensured that myBuffer is a private variable that cannot be accessed or altered outside your code module.
  • Returned maxLength by value instead of the pointer. I don't see why you would need to return it through a pointer.
  • retVal returned through a const pointer.

Coding style changes:

  • Removed U8BIT type and replaced it with C99/C11 compatible uint8_t. If you don't have a C99/C11 compiler, simply typedef unsigned char uint8_t somewhere. This makes your code easier to read by other programmers. If you use your own special types they might incorrectly start to suspect that there is something magic about that particular type.
  • Removed obscure parenthesis around &myBuffer[] since it filled no purpose.
  • Removed magic numbers.

MISRA-C:2004 compliance: (since you tagged this MISRA)

  • u suffix is needed for every integer constant literal.
  • You must typecast the result of the - operator to the underlying type, uint8_t.

Yes, already start to use a const qualified return value.

But you can go further than that, return a value to a place that really isn't modifiable. If I see correctly you only have two possible return values:

... myBuffer... // supposing that this is known at compile time

static U8BIT const retval0 = &(myBuffer[0]);
static U8BIT const retval1 = &(myBuffer[5]);

U8BIT const* fooBuffer(U8BIT * maxLength)
{
    if(isHeaderless()) return &retval0;
    else return &retval1;
}

Your platform may even have means to ensure that the two retval end up in a read-only section.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top