can I require a return value to be a pointer to a constant
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)
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 retval
pointer 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.