/**
* @param[in,out] param Pointer to the destination where to save the value.
*/
void foo(int *param) {
if(param != NULL) {
*param= 100;
}
}
/**
* @param[in,out] param Pointer to the destination where to save the value.
* @retval true Indicates that the value has been successfully saved in \p param.
* @retval false Indicates that the value in \p param could not be saved
* because it points to \c NULL.
*/
bool bar(int *param) {
if(param != NULL) {
*param= 100;
return true;
}
return false;
}
I used the [in,out]
attribute because before changing the destination pointed to by *param
I read the address contained in param
to check that it was different from NULL
.
So the behavior of foo
depends on the value of param
for this reason I used the in
attribute, also the value pointed to by *param
is changed so the out
attribute must also be used.
More generally in C, when you pass a pointer to a function it is normal to check that the address is valid (!= NULL
), in other words you always end up "reading" the parameter forcing you to use the in
attribute even when the parameter is only used to return a value.
I can't think of an example in C where it makes sense to just use the [out]
attribute.
What am I doing wrong in my reasoning?
Adding an example closer to the doubt I'm facing in my project.
In my project I have functions like this, and with mutexFree2()
I can't decide whether to use [in]
or [in,out]
, the goal of the latter is not only to destroy the mutex but also to clean the pointer, so in a way the handle
parameter is also used to return something back.
I really can't make up my mind!
typedef void *mutex_h; // Define mutex handle
/**
* @param[in] handle No doubt, it is an input parameter only.
* @retval true Mutex destroyed.
* @retval false Mutex destruction failed.
*/
bool mutexFree(mutex_h handle) {
// free the mutex
}
/**
* @param[in,out] handle If I only used the [in] attribute it would be like
* saying that this function is the same as mutexFree(), which it is not
* because the goal is also to clear the pointer.
* @retval true Mutex destroyed.
* @retval false Mutex destruction failed.
*/
bool mutexFree2(mutex_h *handle) {
// free the mutex
*handle = NULL;
}
It depends on what exactly you want to document, specifically in case of pointers.
From a technical point of view you could say that all parameters are [in]
because C only has call-by-value, so you cannot pass a modified pointer value to the caller.
Or from a higher level application point of view, param
in bar
is [out]
because you don't read the value pointed to by param
, while the checking for NULL
can be considered as technical error handling and not relevant for the documentation.
In my opinion, your approach of using [in,out]
mixes two things:
[in]
refers to reading the pointer itself[out]
refers to writing to the numberTechnically, it is always necessary to read a pointer unless the pointer parameter is unused. So interpreting [in]
as referring to reading the pointer value does not add valueable information because it is self-evident.
Of course you can have a different opinion in case the pointer value is read for something else than accessing the value it points to.
You could as well have 3 different things if the function would additionally read the value of the number pointed to by param
before modifying it. Then it depends on your interpretation if [in]
refers to reading the pointer itself or reading the pointed-to value.
Example:
/**
* @param[in,out] param Pointer to the value to be modified.
* @retval true Value modified.
* @retval false Invalid pointer value in \p param.
*/
bool baz(int *param) {
if(param != NULL) {
*param += 100;
return true;
}
return false;
}
This function reads the pointer param
for checking, and it reads and writes the number.
I usually consider the purpose of the function. Is the main focus reading or writing the pointed-to value or is it about checking the pointer?
In this case I would consider the NULL
pointer check as less important.
Regarding your function mutexFree2
, I clearly consider it as [out]
because the (pointer) value pointed to by handle
is modified. Depending on what // free the mutex
does, you have to decide if it is also [in]
or not. This decision can be opinion-based.
In contrast to function bar
, this function does not read the (void **
) pointer value for other purposes than accessing the pointed-to value, which is a void *
, so it does not have the ambiguity about what [in]
refers to.