John Vulconshinz
John Vulconshinz

Reputation: 1148

Ignored Semicolon C Syntax

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

Answers (4)

001
001

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

Shafik Yaghmour
Shafik Yaghmour

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

Raymond Chen
Raymond Chen

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

timrau
timrau

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

Related Questions