Reputation: 1148
I am writing a function that returns a pointer to a char. I still want to "return" an integer value that represents what error occured so the function takes as an argument a pointer to an integer that will be used as a flag. Here is an example of the declaration
char* foo(int *flag, etc.)
I want to allow flag
to be NULL if the user does not want to know what specific error happened because it may not matter (I do not know if it does or not, the idea is just theoretical). So I would write the following should an error occur,
... //Symbolic Code
if(error) //Some error has occured
{
if(flag != NULL) *flag = SOME_ERR_VALUE; //Set the flag variable
return NULL; //return NULL to show that an error occured
}
Rather than writing that code over and over again I want to write a macro for it instead. But the code is more than one statement which means I would have to put the macro in it's own code block or the macro would have to be in it's own code block already for example.
#define RETFLAG(err, ret) if(flag != NULL) *flag = err; return ret;
... //Symbolic Code
if(error) //Some error has occured
{RETFLAG(1, NULL)} //Notice the {}
The other way to do it would be,
//Notice the {} in the definition
#define RETFLAG(err, ret) {if(flag != NULL) *flag = err; return ret;}
... //Symbolic Code
if(error) //Some error has occured
RETFLAG(1, NULL)
Both of those methods would work but I do not like the seconded one because I want to put a semicolon at the end of the macro like so,
//Notice the {} in the definition
#define RETFLAG(err, ret) {if(flag != NULL) *flag = err; return ret;}
... //Symbolic Code
if(error) //Some error has occured
RETFLAG(1, NULL); //The only difference is the semicolon
I know the semicolon is unnecessary but I think that it is more readable if you have not actually looked at the definition of RETFLAG. I have already tried to use the unnecessary semicolon and my compiler did not complain and from what I can tell the function worked properly. So my question is, is the unnecessary semicolon legal syntax. If it is legal is it proper?
Upvotes: 2
Views: 284
Reputation: 13533
The comma might help
#define RETFLAG(err, ret) if(flag != NULL) return *flag = err, NULL
Corrected:
#define RETFLAG(err, ret) return NULL == flag ? NULL : *flag = err, NULL
Upvotes: 1
Reputation: 158499
A ;
with no expression is just a null statement and is perfectly legal, from C99 draft standard section 6.8.3
Expression and null statements:
A null statement (consisting of just a semicolon) performs no operations.
But beyond your simple example this has some flaws as Raymond points out in his comment which the do while trick which entails wrapping your code in a do {} while(0)
block, helps overcome, as the accepted answer says:
The do ... while and if ... else are there to make it so that a semicolon after your macro always means the same thing[...]
Upvotes: 2
Reputation: 45173
You don't need a macro at all.
inline char *fail_with_reason(int *flag, int reason)
{
if (flag) *flag = reason;
return NULL;
}
Your function would then say
if (error) return fail_with_reason(flag, 1);
Upvotes: 6
Reputation: 23058
You could use do { ... } while(0)
.
#define RETFLAG(err, ret) do { if(flag != NULL) *flag = (err); return NULL; } while(0)
if (error)
RETFLAG(1, NULL);
This way, you don't need to worry about the scope, and there is no extra semicolon either.
Upvotes: 5