In gatomic.c
of glib there are several function declarations that look like this:
gboolean
(g_atomic_int_compare_and_exchange_full) (gint *atomic,
gint oldval,
gint newval,
gint *preval)
{
return g_atomic_int_compare_and_exchange_full (atomic, oldval, newval, preval);
}
Can someone explain what this code exactly does? I’m confused by several things here:
-
The function name
g_atomic_int_compare_and_exchange_full
is in
parentheses. What’s the significance of this? -
The function’s body apparently consists of nothing but a call to the function itself so this will run forever and result in stack
overflow (pun intended).
I can’t make any sense of this function declaration at all. What’s really going on here?
3
3 Answers
3
Reset to default
Highest score (default)
Trending (recent votes count more)
Date modified (newest first)
Date created (oldest first)
- The function name g_atomic_int_compare_and_exchange_full is in parentheses. What’s the significance of this?
Putting a function name in brackets avoids any macro expansion in case there is a function like macro with the same name.
That means, g_atomic_int_compare_and_exchange_full(...)
will use the macro while (g_atomic_int_compare_and_exchange_full)(...)
will use the function.
Why is this used?
You cannot assign a macro to a function pointer. In that case you can provide the definition as you saw it and then you can use
ptr = g_atomic_int_compare_and_exchange_full;
to use the function instead of the macro.
- The function’s body apparently consists of nothing but a call to the function itself so this will run forever and result in stack overflow (pun intended).
If you look into the associated header gatomic.h
you will see that such a macro is indeed defined. And in the function body, no brackets are used around the function name. That means, the macro is used and it is not an infinite recursion.
0
Answer is given in the comments of the code you’ve linked.
The following is a collection of compiler macros to provide atomic access to integer and pointer-sized values.
And related to @Gerhardh comment, btw.
int (fn)(int param){
fn(param);
}
Defines a function fn
whose action is whatever macro fn
expands too.
The parenthesis around the first occurrence of fn
are there to avoid expansion of this one, which, obviously, would lead to inconsistent code.
Example
sqr.c
#define sqr(x) x*x
int (sqr)(int x){
return sqr(x);
}
main.c
#include <stdio.h>
extern int sqr(int);
int main(){
printf("%dn", sqr(12));
}
Compile with gcc -o main main.c sqr.c
Running ./main
prints 144
. Of course.
But more interestingly, main.c, after preprocessing looks like (gcc -E main.c
)
extern int sqr(int);
int main(){
printf("%dn", sqr(12));
}
(So, sqr
is a function here. If it were a macro, it would have been expanded by now)
And sqr.c
preprocessing gives
int (sqr)(int x){
return x*x;
}
And that the main point: sqr
is a function, whose code is the macro expansion of sqr(x)
.
There is a macro with the name g_atomic_int_compare_and_exchange_full
defined in header gatomic.h
:
#define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval)
(G_GNUC_EXTENSION ({
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));
G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint));
(void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1);
*(preval) = (oldval);
__atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
? TRUE : FALSE;
}))
and there is a function with the same name.
When the name is enclosed in parentheses as here,
gboolean
(g_atomic_int_compare_and_exchange_full) (gint *atomic,
gint oldval,
gint newval,
gint *preval)
then the compiler can not consider it as a macro.
That is, you have a function definition within which there is used a macro with the same name as the name of the function.
Here is a demonstration program:
#include <stdio.h>
#define from( x )( x ) * ( x )
int (from)( int x ) { return from( x ); }
int main( void )
{
printf( "%dn", (from)( 10 ) );
}
Pay attention to that a declarator (including a function declarator) may be enclosed in parentheses.
From the C grammar that defines declarators:
direct-declarator:
identifier
( declarator )
Here is a declaration of a two-dimensional array with enclosing declarators in parentheses:
int ( ( ( a )[10] )[10] );
Though the parentheses evidently are redundant.
1
-
"compiler can not consider it as a macro" – The compiler will never consider stuff as a macro, IMHO. At compilation time, all macros have already been eliminated by the preprocessor.
– Thomas Weller5 hours ago
Your Answer
Sign up or log in
Post as a guest
Required, but never shown
Post as a guest
Required, but never shown
By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.
Not the answer you're looking for? Browse other questions tagged
or ask your own question.
or ask your own question.
Without having the full code, it is hard to tell. Putting a function name in brackets avoids any macro expansion in case there is a function like macro with the same name. That said, this could be a wrapper function for said macro. But that is just guessing.
23 hours ago
Full code is here: gitlab.gnome.org/GNOME/glib/-/blob/main/glib/gatomic.c
23 hours ago
One of my favorite things is when two apparent separate mysteries answer each other.
12 hours ago
|