这是什么疯狂? [英] What is this madness?

查看:79
本文介绍了这是什么疯狂?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从未见过这样的东西;我似乎无法全神贯注.此代码甚至可以做什么?看起来超级花哨,我敢肯定,我的C书中没有任何地方描述这些东西. :(

I've never seen anything like this; I can't seem to wrap my head around it. What does this code even do? It looks super fancy, and I'm pretty sure this stuff is not described anywhere in my C book. :(

union u;
typedef union u (*funcptr)();

union u {
  funcptr f;
  int i;
};

typedef union u $;

int main() {
  int printf(const char *, ...);

  $ fact =
      ($){.f = ({
            $ lambda($ n) {
              return ($){.i = n.i == 0 ? 1 : n.i * fact.f(($){.i = n.i - 1}).i};
            }
            lambda;
          })};

  $ make_adder = ($){.f = ({
                       $ lambda($ n) {
                         return ($){.f = ({
                                      $ lambda($ x) {
                                        return ($){.i = n.i + x.i};
                                      }
                                      lambda;
                                    })};
                       }
                       lambda;
                     })};

  $ add1 = make_adder.f(($){.i = 1});

  $ mul3 = ($){.f = ({
                 $ lambda($ n) { return ($){.i = n.i * 3}; }
                 lambda;
               })};

  $ compose = ($){
      .f = ({
        $ lambda($ f, $ g) {
          return ($){.f = ({
                       $ lambda($ n) {
                         return ($){.i = f.f(($){.i = g.f(($){.i = n.i}).i}).i};
                       }
                       lambda;
                     })};
        }
        lambda;
      })};

  $ mul3add1 = compose.f(mul3, add1);

  printf("%d\n", fact.f(($){.i = 5}).i);
  printf("%d\n", mul3.f(($){.i = add1.f(($){.i = 10}).i}).i);
  printf("%d\n", mul3add1.f(($){.i = 10}).i);
  return 0;
}

推荐答案

此示例主要基于两个GCC扩展:语句表达式.

This example primarily builds on two GCC extensions: nested functions, and statement expressions.

嵌套功能 扩展允许您在另一个函数的主体内定义一个函数.规则的块作用域规则适用,因此嵌套函数在调用时可以访问外部函数的局部变量:

The nested function extension allows you to define a function within the body of another function. Regular block scoping rules apply, so the nested function has access to the local variables of the outer function when it is called:

void outer(int x) {
    int inner(int y) {
        return x + y;
    }
    return inner(6);
}

...
int z = outer(4)' // z == 10

语句表达表达式扩展允许您包装C块语句(通常可以放在花括号中的任何代码:变量声明,for循环等)以用于创造价值的环境.看起来像是括号中的block语句:

The statement expression extension allows you to wrap up a C block statement (any code you would normally be able to place within braces: variable declarations, for loops, etc.) for use in a value-producing context. It looks like a block statement in parentheses:

int foo(x) {
    return 5 + ({
        int y = 0;
        while (y < 10) ++y;
        x + y;
    });
}

...
int z = foo(6); // z == 20

包装的块中的最后一条语句提供了该值.因此,它的工作原理几乎就像您可能想像的是内联函数体.

The last statement in the wrapped block provides the value. So it works pretty much like you might imagine an inlined function body.

这两个扩展的组合使用,使您可以定义一个可以访问周围范围变量的函数体,并在表达式中立即使用它,从而创建一种基本的lambda表达式.由于语句表达式可以包含 any 语句,并且嵌套函数定义是语句,而函数的名称是值,因此语句表达式可以定义函数并立即将指向该函数的指针返回给函数.周围的表情:

These two extensions used in combination let you define a function body with access to the variables of the surrounding scope, and use it immediately in an expression, creating a kind of basic lambda expression. Since a statement expression can contain any statement, and a nested function definition is a statement, and a function's name is a value, a statement expression can define a function and immediately return a pointer to that function to the surrounding expression:

int foo(int x) {
    int (*f)(int) = ({      // statement expression
        int nested(int y) { // statement 1: function definition
            return x + y;
        }
        nested;             // statement 2 (value-producing): function name
    });                     // f == nested

    return f(6); // return nested(6) == return x + 6
}

示例中的代码通过使用美元符号作为返回类型的缩写标识符(被称为 lambda).

The code in the example is dressing this up further by using the dollar sign as a shortened identifier for a return type (another GCC extension, much less important to the functionality of the example). lambda in the example isn't a keyword or macro (but the dollar is supposed to make it look like one), it's just the name of the function (reused several times) being defined within the statement expression's scope. C's rules of scope nesting mean it's perfectly OK to reuse the same name within a deeper scope (nested "lambdas"), especially when there's no expectation of the body code using the name for any other purpose (lambdas are normally anonymous, so the functions aren't expected to "know" that they're actually called lambda).

如果您阅读了有关嵌套函数的GCC文档,则会发现该技术非常有限.嵌套函数在其包含框架的生命周期结束时到期.这意味着它们不能被退回,也不能真正有效地存储.它们可以通过指针向上传递到从包含框架中调用的其他函数中,这些函数期望使用正常的函数指针,因此它们仍然非常有用.但是它们没有真正的lambda灵活,后者拥有所关闭变量的所有权(共享或总计取决于语言),并且可以在所有方向上作为真实值传递或存储以供以后使用.该程序完全无关的部分.即使将其包装在许多帮助程序宏中,该语法也相当笨拙.

If you read the GCC documentation for nested functions, you'll see that this technique is quite limited, though. Nested functions expire when the lifetime of their containing frame ends. That means they can't be returned, and they can't really be stored usefully. They can be passed up by pointer into other functions called from the containing frame that expect a normal function pointer, so they are fairly useful still. But they don't have anywhere near the flexibility of true lambdas, which take ownership (shared or total depends on the language) of the variables they close over, and can be passed in all directions as true values or stored for later use by a completely unrelated part of the program. The syntax is also fairly ungainly, even if you wrap it up in a lot of helper macros.

C很可能在该语言的下一版本(当前称为C2x)中获得真正的lambda.您可以在此处了解更多信息看起来真的很像这样(它复制了Objective-C中发现的匿名函数语法和语义).以这种方式创建的函数的生存期可能会超出其创建范围.函数体是真实的表达式,不需要包含语句的hack;并且函数本身是真正的匿名,不需要像lambda这样的中间名称.

C will most likely be getting true lambdas in the next version of the language, currently called C2x. You can read more about the proposed form here - it doesn't really look much like this (it copies the anonymous function syntax and semantics found in Objective-C). The functions created this way have lifetimes that can exceed their creating scope; the function bodies are true expressions, without the need for a statement-containing hack; and the functions themselves are truly anonymous, no intermediate names like lambda required.

上述示例的C2x版本很可能看起来像这样:

A C2x version of the above example will most likely look something like this:

#include <stdio.h>

int main(void) {
  typedef int (^ F)(int);

  __block F fact;  // needs to be mutable - block can't copy-capture
                   // its own variable before initializing it
  fact = ^(int n) {
    return n == 0 ? 1 : n * fact(n - 1);
  };

  F (^ make_adder)(int) = ^(int n) {
    return _Closure_copy(^(int x) { return n + x; });
  };

  F add1 = make_adder(1);

  F mul3 = ^(int n) { return n * 3; };

  F (^ compose)(F, F) = ^(F f, F g) {
    return _Closure_copy(^(int n) { return f(g(n)); });
  };

  F mul3add1 = compose(mul3, add1);

  printf("%d\n", fact(5));
  printf("%d\n", mul3(add1(10)));
  printf("%d\n", mul3add1(10));

  _Closure_free(add1);
  _Closure_free(mul3add1);

  return 0;
}

没有所有联合的东西就简单得多.

Much simpler without all that union stuff.

(您现在可以在Clang中编译并运行此修改后的示例-使用-fblocks标志启用lambda扩展名,将#include <Block.h>添加到文件顶部,然后将_Closure_copy_Closure_free替换为Block_copyBlock_release.)

(You can compile and run this modified example in Clang right now - use the -fblocks flag to enable the lambda extension, add #include <Block.h> to the top of the file, and replace _Closure_copy and _Closure_free with Block_copy and Block_release respectively.)

这篇关于这是什么疯狂?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆