Reputation: 15057
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)
Upvotes: 0
Views: 192
Reputation: 214780
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:
Coding style changes:
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.MISRA-C:2004 compliance: (since you tagged this MISRA)
u
suffix is needed for every integer constant literal. -
operator to the underlying type, uint8_t.Upvotes: 1
Reputation: 78963
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.
Upvotes: 0
Reputation: 145899
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.
Upvotes: 1
Reputation: 206616
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.
Upvotes: 1