1

I am using clang on linux. What is the correct way to format this block?

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

I am getting an error

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

The error underlines (*func).

I am trying to create a block that takes in a function pointer named func as a parameter and returns a block that calls that func using the arguments it is passed.

14
  • @TypeIA it is "C" Commented May 9, 2018 at 4:06
  • @AnttiHaapala All right, maybe I'm about to learn something... what's up with the carets? Commented May 9, 2018 at 4:08
  • I think it is only technically "C". Blocks are a feature of clang clang.llvm.org/docs/BlockLanguageSpec.html I am trying to learn to use them because I like high order functions. Commented May 9, 2018 at 4:08
  • @TypeIA they're a Clang extension for blocks Commented May 9, 2018 at 4:08
  • In any case, func is a name that perhaps shouldn't be there. Commented May 9, 2018 at 4:09

3 Answers 3

2

The key is the Block_copy function from <Block.h>1. That puts a copy of a block on the heap, which allows the block to be returned.

#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 takes a function pointer as its argument, and returns a block with the signature int (^block)(int, char **).

showFirst is just one possible implementation of the function that can be passed to createBlock. It displays the first string in the argv array and returns the value in argc.

The main function creates a block from the showfirst function. It then invokes the block, prints the returned value, and releases the block.

The output from the code is:

hello
count=3


1 I was not aware of <Block.h> until reading OP's answer.

Sign up to request clarification or add additional context in comments.

Comments

1

http://thirdcog.eu/pwcblocks/ helped a lot.

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

This is a minimum example of accomplishing the goals I outlined in the question.

The trick is the typedefs. Simplify the type signature by creating typedefs to help. I recommend that you use these whenever you want to accept and/or return a function pointer/block pointer.

Block_copy() moves the block from the stack into the heap.

It would be more correct to save the block pointer returned from

f2b(fake_main)

Then after use call

Block_release()

On it.

Comments

1

Your type syntax is incorrect. Based on your usage, I'm guessing you are declaring f2b to be a pointer to a block, which takes a pointer to a function that takes an int and a char ** and returns an int, and the block returns another block that takes an int and a char ** and returns an int.

The proper syntax for that declaration would be:

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

The syntax for more complicated C types is often counter-intuitive, especially in cases of multiple levels of functions and arrays.

The ever-useful cdecl.org website supports blocks: 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 (they say "block" whereas I say "pointer to block")

Your block definition written out using full block literal syntax (including return types) would be something like this (remembering to copy the block in order to return it):

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

Return types may be omitted in block literals, so it could be written like:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.