Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parenthesis operator in C. What is the effect in the following code

Tags:

c

parentheses

I was playing with a macro to enable/disable traces when I came out with the following code when the macro is disabled:

int main()
{

  ("Hello world");

}

This code is valid and I got the desired effect (nothing happens when the macro is disabled) but I couldn't figure out what exactly is happening. Is the compiler seeing the parenthesis as a "nameless" method declaration?

To make it clearer the code is :

 #ifdef TRACE

    #define trace printf("%s %d -> ",__FILE__, __LINE__);printf
 else

    #define trace
 #endif

int main()
{

  trace("Hello world");

}

Thanks in advance.

like image 892
Andre Avatar asked Nov 29 '22 19:11

Andre


2 Answers

If the function name is missing, as in your first example, then it is not a "parenthesis operator". It is simply a syntactic element of an expression that alters the association between operators and operands. In this case it simply does nothing. What you have is just an expression

"Hello world";

which evaluates to a value of char * type, and that value is ignored. You can surround that expression in a redundant pair of ()

("Hello world");

which will not change anything.

In exactly the same way you can write

(5 + 3);

in the middle of your code and get an expression that evaluates to value 8, which is immediately discarded.

Usually compilers generate no code for expression statements that have no side effects. In fact, in C language the result of every expression statement is discarded, so the only expression statements that "make sense" are expression statements with side effects. Compilers are normally fairly good at detecting effectless statements and discarding them (sometimes with a warning).

The warning could be annoying, so writing effectless expression statements like

"Hello world";

might not be a good idea. Typically compilers recognize a cast to void as a request not to generate this warning

(void) "Hello world";

So you might consider redefining your macro accordingly.

Of course, using the above trace technique, you have to remember that if you put something that does have a side effect as an argument for your macro

trace("%d\n", i++);

then in "disabled" form it will look as follows

("%d\n", i++);

(two subexpressions, chained by a comma operator into one expression). The side effect of incrementing i persists in this case, it does not get disabled. The whole thing is equivalent to plain

i++;

Also if you use a function call as an argument

trace(get_trace_name());

the "disabled" form will look as

(get_trace_name());

and the compiler might not be smart enough to realize that the call to get_trace_name() should be discarded. So, be careful when using your macro. Avoid arguments with side effects, avoid arguments with function calls, unless, of course, it is your intent to preserve the side effects when disabling the actual tracing.

like image 60
AnT Avatar answered Dec 10 '22 11:12

AnT


Whether it works or not may depend on exactly what you pass as the arguments to the macro (see the side-effects issue mentioned by AndreyT). In this case it is benign. However the following is probably safer since it will result in no text being inserted when the macro is processed and TRACE is not defined:

#ifdef TRACE
    #define trace printf("%s %d -> ",__FILE__, __LINE__);printf
#else
    #define trace( ... )
#endif

assuming your compiler supports variadic macros. If it does the following would be a better definition perhaps:

#ifdef TRACE
    #define trace( fmt, ...) printf("%s %d -> " fmt, __FILE__, __LINE__, __VA_ARGS__ ) ;
#else
    #define trace( ... )
#endif

Note that the lack of a comma between "%s %d -> " and fmt is deliberate and required. Note also that the fmt argument must be a literal string constant in order for adjacent string literal concatenation to occur - a variable of any kind would generate an error, but it is bad practice to use a variable for a format specifier in any case.

like image 36
Clifford Avatar answered Dec 10 '22 12:12

Clifford