【问题标题】:Block signature for block that takes a function pointer and returns a block块的块签名,它接受一个函数指针并返回一个块
【发布时间】:2018-05-09 03:53:08
【问题描述】:

我在 linux 上使用 clang。 格式化这个块的正确方法是什么?

(int ^(int, char**)) (^f2b)(int, char**) = (int ^(int, char**)) ((int (*func)(int, char**)))
{
  return int ^(int argc, char** argv){ func(argc, argv)};
};

我遇到了一个错误

error: type-id cannot have a name int (^f2b)(int, char**) = (int ^(int, char**)) ((int (*func)(int, char**)))

错误下划线(*func)。

我正在尝试创建一个块,该块接受名为 func 作为参数的函数指针,并返回一个块,该块使用传递的参数调用该 func。

【问题讨论】:

  • @TypeIA 它是“C”
  • @AnttiHaapala 好吧,也许我要学点东西了……插入符号是怎么回事?
  • 我认为它只是技术上的“C”。块是 clang clang.llvm.org/docs/BlockLanguageSpec.html 的一个特性,我正在努力学习使用它们,因为我喜欢高阶函数。
  • @TypeIA 它们是块的 Clang 扩展
  • 无论如何,func 是一个可能不应该出现的名字。

标签: c clang objective-c-blocks


【解决方案1】:

关键是来自<Block.h>1Block_copy 函数。这会将一个块的副本放在堆上,从而允许返回该块。

#include <stdio.h>
#include <Block.h>

typedef int (^block_t)(int, char **);
typedef int (*func_t)(int, char **);

block_t (^createBlock)(func_t func) = ^(func_t func)
{
    return Block_copy( ^(int argc, char **argv) { return func(argc, argv); } );
};

int showFirst(int argc, char *argv[])
{
    printf("%s\n", argv[0]);
    return argc;
}

int main(void)
{
    int argc = 3;
    char *argv[] = {"hello", "world", NULL};

    block_t block1 = createBlock(showFirst);
    int count = block1(argc, argv);
    printf("count=%d\n", count);
    Block_release(block1);
}

createBlock 将函数指针作为其参数,并返回一个带有签名int (^block)(int, char **) 的块。

showFirst 只是可以传递给createBlock 的函数的一种可能实现。它显示argv 数组中的第一个字符串并返回argc 中的值。

main 函数从showfirst 函数创建一个块。然后它调用块,打印返回值,然后释放块。

代码的输出是:

你好
计数=3


1 在阅读 OP 的答案之前,我不知道 &lt;Block.h&gt;

【讨论】:

    【解决方案2】:

    http://thirdcog.eu/pwcblocks/ 帮了大忙。

    #include <stdlib.h>
    #include <stdio.h>
    #include <Block.h>
    
    int fake_main(int argc, char** words)
    {
      printf("%s\n", (char*)words);
      return argc;
    }
    
    int main(int argc, char* argv[])
    {
      typedef int(*main_type_func)(int, char**);
      typedef int(^main_type)(int, char**);
      typedef main_type(^f2b_type)(main_type_func);
    
      f2b_type f2b = ^ (main_type_func func)
        {
          return Block_copy(^ (int apple, char** ban)
          {
            return func(apple, ban);
          });
        };
    
      printf("%d\n", f2b(fake_main)(1, "words worked"));
    }
    

    这是实现我在问题中概述的目标的一个最小示例。

    诀窍在于 typedef。通过创建 typedef 来帮助简化类型签名。我建议您在想要接受和/或返回函数指针/块指针时使用它们。

    Block_copy() 将块从堆栈移动到堆中。

    保存返回的块指针会更正确

    f2b(fake_main)
    

    然后使用后调用

    Block_release()
    

    就可以了。

    【讨论】:

      【解决方案3】:

      您的类型语法不正确。根据您的使用情况,我猜您将 f2b 声明为指向块的指针,该块采用指向函数的指针,该函数采用 intchar ** 并返回 int,并且块返回另一个块,它接受一个int 和一个char ** 并返回一个int

      该声明的正确语法是:

      int (^(^f2b)(int (*) (int, char **)))(int, char **)
      

      更复杂的 C 类型的语法通常是违反直觉的,尤其是在函数和数组的多个级别的情况下。

      非常有用的 cdecl.org 网站支持块:declare f2b as block(pointer to function(int, pointer to pointer to char) returning int) returning block(int, pointer to pointer to char) returning int(他们说“块”,而我说“指向块的指针”)

      使用完整的块文字语法(包括返回类型)写出的块定义将是这样的(记住复制块以返回它):

      int (^(^f2b)(int (*) (int, char **)))(int, char **) =
      ^int (^(int (*func)(int, char **)))(int, char **) {
          return Block_copy(^int (int argc, char **argv) {
              return func(argc, argv);
          });
      };
      

      返回类型可以在块字面量中省略,所以可以这样写:

      int (^(^f2b)(int (*) (int, char **)))(int, char **) =
      ^(int (*func)(int, char **)) {
          return Block_copy(^(int argc, char **argv) {
              return func(argc, argv);
          });
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-19
        • 1970-01-01
        • 2014-08-13
        • 2020-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多