一个C函数声明在括号中,显然永远调用它自己,这有什么意义?

ldioqlga  于 2023-08-03  发布在  其他
关注(0)|答案(5)|浏览(105)

在glib的gatomic.c中,有几个函数声明如下所示:

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);
}

字符串
有人能解释一下这段代码到底是做什么的吗?我对这里的几件事感到困惑:
1.函数名g_atomic_int_compare_and_exchange_full在括号中。这有什么意义
1.这个函数的函数体除了对函数本身的调用外什么都没有,所以这将永远运行并导致堆栈溢出(双关语)。
我完全搞不懂这个函数声明。这到底是怎么回事

ivqmmu1c

ivqmmu1c1#

1.函数名g_atomic_int_compare_and_exchange_full在括号中。这有什么意义
将函数名放在方括号中可以避免任何宏扩展,以防存在同名的函数(如宏)。
这意味着,g_atomic_int_compare_and_exchange_full(...)将使用宏,而(g_atomic_int_compare_and_exchange_full)(...)将使用函数。
为什么使用这个?不能将宏赋给函数指针。在这种情况下,您可以提供所看到的定义,然后可以使用

ptr = g_atomic_int_compare_and_exchange_full;

字符串
使用函数而不是宏。
1.这个函数的函数体除了对函数本身的调用外什么都没有,所以这将永远运行并导致堆栈溢出(双关语)。
如果查看相关的头文件gatomic.h,您将看到确实定义了这样一个宏。在函数体中,函数名周围没有括号。这意味着,使用了宏,并且它不是无限递归。

nc1teljy

nc1teljy2#

答案在您链接的代码的注解中给出。
以下是编译器宏的集合,可提供对整数和指针大小的值的原子访问。
顺便说一句,和@Gerhardh评论有关。

int (fn)(int param){
    fn(param);
}

字符串
定义一个函数fn,它的操作也是宏fn展开的任何内容。
在第一次出现fn时加上圆括号是为了避免扩展,这显然会导致代码不一致。
范例

平方c

#define sqr(x) x*x
int (sqr)(int x){
   return sqr(x);
}

主要.c

#include <stdio.h>
extern int sqr(int);
int main(){
    printf("%d\n", sqr(12));
}


使用gcc -o main main.c sqr.c编译
运行./main将打印144。当然可以了。
但更有趣的是,main. c在预处理后看起来像(gcc -E main.c

extern int sqr(int);
int main(){
    printf("%d\n", sqr(12));
}


(So,sqr在这里是一个函数。如果它是宏,现在应该已经展开了)
sqr.c预处理给出了

int (sqr)(int x){
   return x*x;
}


而这主要的一点:sqr是一个函数,它的代码是sqr(x)的宏扩展。

whlutmcx

whlutmcx3#

在header gatomic.h中定义了一个名为g_atomic_int_compare_and_exchange_full的宏:

#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;                               \
  }))

字符串
还有一个同名函数。
当名称用括号括起来时,

gboolean
(g_atomic_int_compare_and_exchange_full) (gint *atomic,
                                          gint  oldval,
                                          gint  newval,
                                          gint *preval)


那么编译器不能将其视为宏。
也就是说,你有一个函数定义,其中使用了一个与函数名称相同的宏。
下面是一个演示程序:

#include <stdio.h>

#define from( x )( x ) * ( x )

int (from)( int x ) { return from( x ); }

int main( void )
{
    printf( "%d\n", (from)( 10 ) );
}


注意声明符(包括函数声明符)可能会被括号括起来。
从定义声明符的C语法中:

direct-declarator:
    identifier
    ( declarator )


下面是一个二维数组的声明,括号中有封闭声明符:

int ( ( ( a )[10] )[10] );


尽管括号显然是多余的。

2jcobegt

2jcobegt4#

正如其他人所说,这允许将某个对象定义为类似函数的宏和真实的函数。
你为什么要这么做?我可以看到几个原因。
1.向后兼容性。库作者可能出于性能或灵活性原因而从真实的函数切换到类函数宏,但仍希望保持与调用实函数的现有二进制文件的兼容性。
1.与其他编程语言兼容。用C语言编写的宏只能在C和C++等语言中有效使用,这些语言或多或少都是C的扩展。真实的函数可以从任何支持C调用约定的语言中调用。
1.真实的函数可以与函数指针一起使用,而类似函数的宏则不能。

ej83mcc0

ej83mcc05#

您提供的代码不是完整的函数定义,而是实际函数g_atomic_int_compare_and_exchange_full的“ Package 器”或“函数别名”。让我们分解一下这里发生的事情:
1.函数别名:您提供的代码为函数g_atomic_int_compare_and_exchange_full创建了一个别名。别名是用括号括住函数名创建的,后面是函数的参数列表和函数体。此技术通常在宏中用于定义类似函数的宏。在本例中,宏似乎与实际函数有别名。
1.递归调用:你是对的,代码,因为它是,似乎导致一个递归调用,这将导致堆栈溢出。然而,这个代码片段可能是一个更大的上下文的一部分,函数g_atomic_int_compare_and_exchange_full的真实的定义应该在其他地方。真实的的函数应该有一个正确的实现,而不是对自身的递归调用。
为了更清楚地说明这一点,g_atomic_int_compare_and_exchange_full的实际实现应该在其他地方定义,它可能看起来像这样:

gboolean g_atomic_int_compare_and_exchange_full(gint *atomic,
                                                gint oldval,
                                                gint newval,
                                                gint *preval)
{
  // Actual implementation of the atomic compare and exchange operation
  // This function performs an atomic compare-and-exchange on the given integer value.
  // It compares the value at the memory location "atomic" with "oldval", and if they are equal,
  // it updates the value at "atomic" to "newval". The current value at "atomic" is returned in "preval".

  // ... Implementation details ...
  // (Actual atomic compare-and-exchange code)
  // ...

  return TRUE; // or FALSE, depending on whether the exchange was successful
}

字符串

相关问题