55

这个问题不是很具体。这真的是为了我自己的 C 丰富,我希望其他人也能发现它有用。

免责声明:我知道很多人会冲动地回应“如果你正在尝试做 FP,那么就使用函数式语言”。我在需要链接到许多其他 C 库的嵌入式环境中工作,并且没有太多空间容纳更多大型共享库,并且不支持许多语言运行时。此外,动态内存分配是不可能的。我也只是很好奇。

我们中的许多人都看过这个用于 lambda 表达式的漂亮 C 宏:

#define lambda(return_type, function_body) \
({ \
      return_type __fn__ function_body \
          __fn__; \
})

一个示例用法是:

int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; });
max(4, 5); // Example

使用gcc -std=c89 -E test.c,lambda 扩展为:

int (*max)(int, int) = ({ int __fn__ (int x, int y) { return x > y ? x : y; } __fn__; });

所以,这些是我的问题:

  1. 行int (*X);究竟是什么?宣布?当然,int * X;是指向整数的指针,但这两者有何不同?

  2. 看看扩展的宏,final到底是__fn__做什么的?如果我编写一个测试函数void test() { printf("hello"); } test;- 会立即引发错误。我不明白那种语法。

  3. 这对调试意味着什么?(我打算用这个和gdb来试验自己,但其他人的经验或意见会很棒)。这会搞砸静态分析仪吗?

4

4 回答 4

42

此声明(在块范围内):

int (*max)(int, int) =
    ({
    int __fn__ (int x, int y) { return x > y ? x : y; }
    __fn__;
    });

不是 C,而是有效的 GNU C。

它使用了两个gcc扩展:

  1. 嵌套函数
  2. 语句表达式

嵌套函数(在复合语句中定义函数)和语句表达式({}),基本上是一个产生值的块)在 C 中都是不允许的,它们来自 GNU C。

在语句表达式中,最后一个表达式语句是构造的值。这就是嵌套函数__fn__出现在语句表达式末尾的表达式语句的原因。表达式中的函数指示符(__fn__在最后一个表达式语句中)通过通常的转换转换为指向函数的指针。这是用于初始化函数指针的值max

于 2012-05-01T23:04:24.323 回答
6

您的 lambda 宏利用了两个时髦的功能。首先,它使用嵌套函数来实际定义函数的主体(因此您的 lambda 并不是真正匿名的,它只是使用一个隐式__fn__变量(应该将其重命名为其他东西,因为双前导下划线名称是为编译器保留的,所以也许类似的东西yourapp__fn__会更好)。

所有这些都是在 GCC 复合语句中执行的(参见http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs),其基本格式类似于:

({ ...; retval; })

复合语句的最后一条语句是刚刚声明的函数的地址。现在,int (*max)(int,int)只需分配复合语句的值,它现在是指向刚刚声明的“匿名”函数的指针。

调试宏当然是一件非常痛苦的事情。

至于为什么test;..至少在这里,我得到'测试重新声明为不同类型的符号',我认为这意味着GCC将其视为声明而不是(无用的)表达式。因为无类型变量默认为int并且因为你已经声明test为一个函数(本质上,void (*)(void))你明白了..但我可能错了。

无论如何,这都不是可移植的。

于 2012-05-01T23:23:29.157 回答
1

部分答案:您感兴趣的不是 int(*X)。它是 int (*X)(y,z)。那是一个指向名为 X 的函数的函数指针,它接受 (y,z) 并返回 int。

对于调试,这将非常困难。大多数调试器无法通过宏进行跟踪。您很可能必须调试程序集。

于 2012-05-01T22:51:50.377 回答
0
  1. int (*max)(int, int)是您要声明的变量的类型。它被定义为一个名为 max 的函数指针,它返回 int,并以两个 int 作为参数。

  2. __fn__指函数名,在本例中为 max。

  3. 我在那里没有答案。我想如果您通过预处理器运行它,您可以逐步完成它。

于 2012-05-01T22:50:18.633 回答